Skip to content

math-u-t/appsscript-cli

Repository files navigation

gscript - TypeScript Development for Google Apps Script

License: MIT TypeScript Node

A CLI tool that brings TypeScript-style development experience to Google Apps Script with real-time compatibility checking, auto-fix capabilities, and seamless deployment.

✨ Features

  • 🔍 Real-time Compatibility Checking - Detects incompatible Web APIs before deployment
  • 🔧 Auto-fix Engine - Automatically fixes common compatibility issues
  • 📘 Complete Type Definitions - Full TypeScript support for all Apps Script services
  • 🏗️ Modern File Structure - Organize code in multiple files, automatically bundled
  • Fast Development - Hot reload, mock services, integrated testing
  • 🚀 Easy Deployment - One-command deployment to Apps Script
  • 📚 Comprehensive Documentation - Detailed guides and examples

🚀 Quick Start

Installation

npm install -g gscript

Create a New Project

gscript init my-project
cd my-project
npm install

Write Code with Type Safety

// src/main.ts
function doGet(e: GoogleAppsScript.Events.DoGet) {
  return HtmlService.createHtmlOutput('<h1>Hello, World!</h1>');
}

function sendEmail(to: string, subject: string, body: string): void {
  GmailApp.sendEmail(to, subject, body);
}

Check for Compatibility Issues

gscript check

Example output:

error: Incompatible API usage (GLOBAL_FETCH)
  --> src/api.ts:15:10
   |
15 | const response = fetch('https://api.example.com');
   |                  ^^^^^
   |
   = help: Use UrlFetchApp.fetch() instead
   = docs: https://developers.google.com/apps-script/reference/url-fetch

Auto-fix Issues

gscript check --fix

Automatically converts:

  • fetch()UrlFetchApp.fetch()
  • crypto.randomUUID()Utilities.getUuid()
  • Removes import/export statements
  • And more...

Build and Deploy

# Build project
gscript build

# Deploy to Apps Script
gscript deploy

📋 What Gets Checked?

❌ Incompatible APIs Detected

// Web APIs (not available in Apps Script)
fetch('url')                           Use UrlFetchApp.fetch()
crypto.randomUUID()                    Use Utilities.getUuid()
localStorage.setItem('key', 'value')   Use PropertiesService
setTimeout(() => {}, 1000)             Use Utilities.sleep() or triggers
process.env.API_KEY                    Use PropertiesService

// Node.js APIs
const fs = require('fs')               Use DriveApp
Buffer.from('data')                    Use Utilities.base64Encode()

// ES Modules
import { foo } from './bar'            Removed during build
export function baz() {}               Removed during build

✅ Apps Script Equivalents Provided

// HTTP Requests
const response = UrlFetchApp.fetch('https://api.example.com', {
  method: 'post',
  payload: JSON.stringify({ key: 'value' }),
  headers: { 'Authorization': 'Bearer token' }
});

// UUID Generation
const id = Utilities.getUuid();

// Hashing
const hash = Utilities.computeDigest(
  Utilities.DigestAlgorithm.SHA_256,
  'data'
);

// Storage
const props = PropertiesService.getUserProperties();
props.setProperty('key', 'value');
const value = props.getProperty('key');

// File Operations
const file = DriveApp.createFile('name.txt', 'content');
const content = file.getBlob().getDataAsString();

📖 Documentation

🎯 Use Cases

Web Application

function doGet(e: GoogleAppsScript.Events.DoGet) {
  return HtmlService.createHtmlOutput(getTemplate());
}

function doPost(e: GoogleAppsScript.Events.DoPost) {
  const data = JSON.parse(e.postData.contents);
  processData(data);
  return ContentService.createTextOutput(JSON.stringify({ success: true }))
    .setMimeType(ContentService.MimeType.JSON);
}

Email Automation

function processInvoices() {
  const threads = GmailApp.search('is:unread subject:invoice');

  threads.forEach(thread => {
    const messages = thread.getMessages();
    const invoice = extractInvoiceData(messages[0]);
    saveToSpreadsheet(invoice);
    thread.markRead();
  });
}

Data Integration

function syncData() {
  const response = UrlFetchApp.fetch('https://api.example.com/data', {
    headers: { 'Authorization': `Bearer ${getApiKey()}` }
  });

  const data = JSON.parse(response.getContentText());
  updateSpreadsheet(data);
}

function getApiKey(): string {
  return PropertiesService.getScriptProperties().getProperty('API_KEY')!;
}

🛠️ CLI Commands

Command Description
gscript init [name] Initialize new project
gscript check Check compatibility issues
gscript check --fix Auto-fix issues
gscript build Build for deployment
gscript deploy Deploy to Apps Script
gscript dev Start development server
gscript pull Pull from Apps Script
gscript logs View execution logs
gscript test Run test suite

⚙️ Configuration

gscript.config.json

{
  "projectId": "your-script-id",
  "runtime": "V8",
  "timeZone": "America/New_York",
  "oauthScopes": [
    "https://www.googleapis.com/auth/script.external_request",
    "https://www.googleapis.com/auth/gmail.send",
    "https://www.googleapis.com/auth/drive"
  ],
  "webApp": {
    "access": "ANYONE_ANONYMOUS",
    "executeAs": "USER_ACCESSING"
  },
  "compatibility": {
    "strictMode": true,
    "warningsAsErrors": false
  }
}

📦 Examples

Check out the examples directory:

🔄 Comparison with clasp

Feature clasp gscript
TypeScript Support
Compatibility Checking
Auto-fix
Type Definitions Manual Included
File Bundling Manual Automatic
Development Server
Error Messages Basic Detailed

gscript works alongside clasp! Use both tools together for the best experience.

🏗️ Project Structure

project/
├── src/
│   ├── main.ts              # Entry point
│   ├── utils/
│   │   └── helpers.ts
│   └── services/
│       └── gmail.ts
├── tests/
│   └── main.test.ts
├── dist/                     # Build output (auto-generated)
│   ├── Code.gs
│   └── appsscript.json
├── gscript.config.json       # gscript configuration
├── .clasp.json               # Apps Script project
├── tsconfig.json             # TypeScript configuration
└── package.json

🧪 Development

Build from Source

git clone https://github.com/your-org/gscript.git
cd gscript
npm install
npm run build

Run Tests

npm test

Link Locally

npm link
gscript --version

📊 Compatibility Rules

gscript uses a comprehensive compatibility database:

  • 50+ global API checks (fetch, crypto, localStorage, etc.)
  • 30+ Node.js API checks (fs, path, process, etc.)
  • 20+ pattern-based checks (import/export, async/await, etc.)
  • Runtime-specific checks (V8 vs RHINO features)

See compatibility-rules.json for the complete list.

🎓 Learning Resources

🤝 Contributing

Contributions are welcome! Please see CONTRIBUTING.md for guidelines.

Adding Compatibility Rules

Edit compatibility-rules.json:

{
  "globals": {
    "yourApi": {
      "available": false,
      "replacement": "AppsScriptEquivalent",
      "message": "Use AppsScriptEquivalent instead",
      "severity": "error",
      "autofix": true
    }
  }
}

📜 License

MIT License - see LICENSE file for details.

🙏 Acknowledgments

  • Built on top of clasp by Google
  • Uses @typescript-eslint for AST parsing
  • Inspired by the TypeScript compiler's error messages

📞 Support

🎯 Roadmap

  • VS Code extension for inline validation
  • GitHub Actions integration
  • Interactive development server
  • Automated testing framework
  • Performance profiling tools
  • Bundle size optimization
  • Source maps support
  • Watch mode for auto-rebuild

Made with ❤️ for the Apps Script community


Quick Links

About

appsscriptのcli

Resources

License

Contributing

Stars

Watchers

Forks

Releases

No releases published

Packages

No packages published

Contributors 2

  •  
  •