Code Monkey home page Code Monkey logo

ts2gas's Introduction

ts2gas

Unit CI Lint CI

A function that transpiles TypeScript to Google Apps Script.

ts2gas(code: string, transpileOptions?: ts.TranspileOptions): string

For example the code below

const writeToLog = (message: string) => console.info(message);

let words = ['hello', 'world'];
writeToLog(`${words.join(' ')}`);

gets transpiled into

// Compiled using ts2gas 1.3.0 (TypeScript 3.2.2)
var exports = exports || {};
var module = module || { exports: exports };
var writeToLog = function (message) { return console.info(message); };
var words = ['hello', 'world'];
writeToLog("" + words.join(' '));

Install

npm i ts2gas

Usage

Write Apps Script as TypeScript without including any imports.

const ts2gas = require('ts2gas');

let transpiled = ts2gas(`
function buildName(first:string, last:string) {
  return \`\${firstName} \${lastName}\`;
}
`);

// Transpiles to:
// function buildName(first, last) {
//   return firstName + " " + lastName;
// }

Advanced

Transpiler is called with this default ts.TranspileOptions object

{
  compilerOptions: {
    experimentalDecorators: true,
    isolatedModules: true,
    module: "None",
    noImplicitUseStrict: true,
    noLib: true,
    noResolve: true,
    target: "ES3",
  },
  // the following property is to document this little known feature
  // renamedDependencies: { SomeName: 'SomeOtherName' },
}

ts2gas can accepts a custom ts.TranspileOptions object as second parameter.

ts2gas(source: string, transpileOptions: ts.TranspileOptions = {}): string

Note that the following compilerOptions cannot be changed:

{
  isolatedModules: true,
  module: "None",
  noLib: true,
  noResolve: true,
}

TypeScript Tests

Some samples of TypeScript derived from https://angular-2-training-book.rangle.io/handout/features/

class Hamburger {
  constructor() {
    // This is the constructor.
  }
  listToppings() {
    // This is a method.
  }
}

// Template strings
var name = 'Grant';
var age = 42;
console.log(`Hello! My name is ${name}, and I am not ${age} years old.`);

// Rest args
const add = (a, b) => a + b;
let args = [3, 5];
add(...args); // same as \`add(args[0], args[1])\`, or \`add.apply(null, args)\`

// Spread array
let cde = ['c', 'd', 'e'];
let scale = ['a', 'b', ...cde, 'f', 'g'];  // ['a', 'b', 'c', 'd', 'e', 'f', 'g']

// Spread map
let mapABC  = { a: 5, b: 6, c: 3};
let mapABCD = { ...mapABC, d: 7};  // { a: 5, b: 6, c: 3, d: 7 }

// Destructure
let jane = { firstName: 'Jane', lastName: 'Doe'};
let john = { firstName: 'John', lastName: 'Doe', middleName: 'Smith' }
function sayName({firstName, lastName, middleName = 'N/A'}) {
  console.log(`Hello ${firstName} ${middleName} ${lastName}`)
}
sayName(jane) // -> Hello Jane N/A Doe
sayName(john) // -> Helo John Smith Doe

// Export
export const pi = 3.141592;
function add(x: number, y: number): number {
    return x + y;
}
console.log(add(2, 2)); // 4

// Decorators
function Override(label: string) {
  return function (target: any, key: string) {
    Object.defineProperty(target, key, {
      configurable: false,
      get: () => label
    });
  }
}
class Test {
  @Override('test')      // invokes Override, which returns the decorator
  name: string = 'pat';
}
let t = new Test();
console.log(t.name);  // 'test'

ts2gas's People

Contributors

dependabot[bot] avatar grant avatar popgoesthewza avatar pozhidaevak avatar takanakahiko avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar

ts2gas's Issues

TypeScript 3.* support

ts2gas currently support TypeScript up to 2.9.2. Is there any reason to this limit (beside the package.json dependency of course) ?

Multi-line import statements creates invalid Apps Script

Expected Behavior

Multi-line typescript import statements translated correctly

Actual Behavior

The translated Apps Script code is invalid

Steps to Reproduce the Problem

  1. Create a multi-line typscript import statement such as
import {
  FinancialTransactionFromSpreadsheet,
  SpreadSheetDef
} from "./financial.transaction.from.spreadsheet";
  1. Have clasp push to remote project

The translated code will have a "\n" embedded along with invalid lines:

//import {
\n  FinancialTransactionFromSpreadsheet,
  SpreadSheetDef
} from "./financial.transaction.from.spreadsheet";

Attempting to run the code will produce the error message
Illegal character.

Specifications

  • Node version (node -v): 11.8.0
  • Version (clasp -v): 2.0.1
  • OS (Mac/Linux/Windows): Windows

noSubstitutionBeforeBuilder cannot correctly convert try-catch clauses containing asycn / await.

Input Source Code

async function main() {
  try {
    await wait(1000);
  } catch (error) {
    console.log(error);
  }
}

Build with ts2gas

// ...
function main() {
    return __awaiter(this, void 0, void 0, function () {
        var error_1;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    _a.trys.push([0, 2, , 3]);
                    return [4 /*yield*/, wait(1000)];
                case 1:
                    _a.sent();
                    return [3 /*break*/, 3];
                case 2:
                    error_1 = _a.sent();
                    console.log(error);      // <-------- It will be treated as ReferenceError.
                    return [3 /*break*/, 3];
                case 3: return [2 /*return*/];
            }
        });
    });
}

Conversion with TypeScript Playground

// ...
function main() {
    return __awaiter(this, void 0, void 0, function () {
        var error_1;
        return __generator(this, function (_a) {
            switch (_a.label) {
                case 0:
                    _a.trys.push([0, 2, , 3]);
                    return [4 /*yield*/, wait(1000)];
                case 1:
                    _a.sent();
                    return [3 /*break*/, 3];
                case 2:
                    error_1 = _a.sent();
                    console.log(error_1);      // <-------- here
                    return [3 /*break*/, 3];
                case 3: return [2 /*return*/];
            }
        });
    });
}

The judgment here seems to be wrong.

Error in tsconfig.json when npm installed

I ran npm install ts2gas and installed version 1.6.0. My IDE warns me about an error in the "tsconfig.json" file:

File '/Users/.../node_modules/ts2gas/src/index.ts' not found.

Is something configured incorrectly?

Inheritance class becomes TypeError in load order.

Just because the inherited class has a different loading order(alphabetical), it becomes "TypeError: Cannot read property 'prototype' of undefined". Screen shot

I created a sample project to convey this.

Expected Behavior

case OK:
https://github.com/jakenjarvis/clasp-ts-sample/tree/master/IssueSample/Issue01/ProjectNormal

Actual Behavior

case NG:
https://github.com/jakenjarvis/clasp-ts-sample/tree/master/IssueSample/Issue01/ProjectAbnormal

TypeError: Cannot read property 'prototype' of undefined (line 14, file "AClass")

Steps to Reproduce the Problem

  1. Swap the class names of AClass and BClass.
  2. Oh wonder, it becomes TypeError.

Specifications

  • Windows 10 64bit
  • node v10.15.0
  • yarn 1.13.0
  • @google/clasp 1.6.3
  • @types/google-apps-script 0.0.36

I posted the same issue here(Clasp#527). I was urged to instead Issue to ts2gas.

(Minor) some comments around ignored statements are lost through transpileModule

Excerpt from current npm run test, notice how the first comment next statement will be ignored is missing from the output.

# testMultilineExports
v--TS--v
// next statement will be ignored
export { foo, bar }
  from "file";
// next statement will be preserved
...
–––
// Compiled using ts2gas 1.5.1 (TypeScript 3.2.2)
var exports = exports || {};
var module = module || { exports: exports };
//export { foo, bar }\n  from "file";
// next statement will be preserved
...
^--GS--^

When applying transformers over statements to ignore, leaning/trailing comments attributes should be checked and applied to the transformed statements.

Pro-tip use this AST explorer online tool to explorer the transpileModule AST tree https://astexplorer.net/ (I wish I knew about it when I first wrote the ts2gas transformers)

image

Variable names changed when using import

// foo.ts
import Module from 'TypeScriptModule';
const module = new Module();

It transpiled below:

// foo.gs
var module = new TypeScriptModule_1["default"]()

So, TypeScriptModule_1 is not found error has occuerd.


I know ignoring import/export statements has merged at issue#5, and it's a great work!
Adding _1 into module variable name when using TS module import, is it properly transpiling or not ?
If it's correct convert of TypeScript, I should update my TypeScript codes for Google Apps Script.
How should I do ?

@grant @PopGoesTheWza

require and import

There's a note in the readme indicating that noLib is fixed at false. Does that mean ts2gas does not currently handle imports? Like, I'm trying to import a module, but nothing seems to happen.

Thanks.

Imports are not removed during transpilation.

The import statement is auto-created in IntelliJ but cannot be pushed to Apps Script. Comment these lines out.

import GmailMessage = GoogleAppsScript.Gmail.GmailMessage;

function getCurrentMessage():GmailMessage {
  return GmailApp.createDraft("", "", "").send()
}

getCurrentMessage();

Note: this will not prevent multi-line imports.

Improper conversion of [...string]

In VSCode I have

const Reverse = (string:string) => [...string].reverse().join('');

ts2gas converts this to

var Reverse = function (string) { return string.slice().reverse().join(''); };

which fails because slice does not convert string into an array, which reverse() requires. There is a String.prototype.slice but it is not the same as Array.prototype.slice.

No index.js

I installed ts2gas with @google/crasp by npm. But it does not work.

Error: Cannot find module 'ts2gas'
at Function.Module._resolveFilename (module.js:469:15)
at Function.Module._load (module.js:417:25)
at Module.require (module.js:497:17)
at require (internal/module.js:20:19)
at Object. (C:\Users<user>\AppData\Roaming\npm\node_modules@google \clasp\src\files.js:44:14)
at Module._compile (module.js:570:32)
at Object.Module._extensions..js (module.js:579:10)
at Module.load (module.js:487:32)
at tryModuleLoad (module.js:446:12)
at Function.Module._load (module.js:438:3)

After investigation, I fount [email protected] did not have "index.js" at local (i.e. at my PC).

So, please include index.js at npm modules.

Requiring tslib in transpiled code

Hi there! Firstly, thanks a tonne for this great utility and all your hard work, it's much appreciated.

I've been using Google's clasp to push TypeScript based Apps Scripts projects, and it was working as expected for a couple of weeks. Then recently I've found that the conversion from TypeScript has begun generating gas code that doesn't work. It seems that there is a line in the transpiled code as follows:

var tslib_1 = require("tslib");

This throws an error as require isn't supported. I can see that it seems to be related to using the following features (but not limited to them):

  • async/await
  • async generators
  • rest operators

I did a little digging through my previous transpilations that worked, and I can see that in those instances the required polyfills from tslib were being injected into the transpiled code.

Do you have any thoughts on what may be happening here? Could it be an issue related to clasp and not ts2gas?

This is screwing up arguments with default values

Hello,

The following only holds if Google is using your library, as it seems. Transpiled files now start with this commend: "// Compiled using ts2gas 1.5.0 (TypeScript 3.2.4)"

Just started getting "InternalErrors" in appscript recently and it seems due to how ts2gas handles arguments with default values.

For example,

function JsonResponseHandler(url: string, query = {}, params = {muteHttpExceptions: true}, cacheName: string, cacheTime = 3600) {
...
}

This is now getting converted to this:

function JsonResponseHandler(url, query, params, cacheName, cacheTime) {
    if (query === void 0) {  }
    if (params === void 0) {  }
    if (cacheTime === void 0) {  }
}

Which sucks, because I now need to rejigger my code to get around this as the ts2gas is getting rid of default values for arguments.

Is this a bug or a matter of adjusting my typescript code?

Thank you!

function imports are strange

I wrote a test:

    printBeforeAndAfter(
      `import {foo} from './another_place';

foo()`,
    );

Here's the output:

# testImport
v--TS--v
import {foo} from './another_place';

foo()
---
// Compiled using ts2gas 4.2.0 (TypeScript 4.9.3)
var exports = exports || {};
var module = module || { exports: exports };
//import {foo} from './another_place';
(0, another_place_1.foo)();
^--GS--^

Expected output:

# testImport
v--TS--v
import {foo} from './another_place';

foo()
---
// Compiled using ts2gas 4.2.0 (TypeScript 4.9.3)
var exports = exports || {};
var module = module || { exports: exports };
//import {foo} from './another_place';
foo();
^--GS--^

Alternatively, if another_place.ts exports files, a different expectation would be for another_place.ts to define another_place_1 as its export variable:

var another_place_1 = another_place_1 || {};
var exports = exports || {};

// ...

exports.foo = another_place_1.foo = 'foo';

Or a namespace...

another_place.ts

namespace another_place_1 {
    export function foo() {}
}

main.ts

// import {foo} from './another_place';
const {foo} = another_place_1;

transformer `removeExportEsModule`is overdoing it

Sample test with missing exports

# testNamespace
v--TS--v
namespace Pop {
  export const goes = 'Goes';
  export function The(): void {}
  export class Wza {}
  }
–––
// Compiled using ts2gas 1.5.0 (TypeScript 3.2.2)
var exports = exports || {};
var module = module || { exports: exports };
var Pop;
(function (Pop) {
    Pop.goes = 'Goes';
    function The() { }
    var Wza = /** @class */ (function () {
        function Wza() {
        }
        return Wza;
    }());
})(Pop || (Pop = {}));
 ^--GS--^

Support transpilation for V8 runtime

Related to google/clasp#735
https://developers.google.com/apps-script/guides/v8-runtime/migration

Now that we can use V8 runtime in GAS, it's better to generate less-transpiled files for it.
There are some options for the way to support the feature.

  1. make "target" option injectable.
  2. pass runtimeType as the third argument // type RuntimeType = "V8" | "Rhino"
  3. export two functions: ts2gasV8 and ts2GasRhino

If you tell me which one is the best, I'm ready for PR for this.

Comment out `export *` statements

Export statements like export * from "file" should be commented out as they are translated to code with require() that is not supported by google script
However export val and export function seem to work fine.

@grant also suggested to comment out __export()

Will try to create a PR for this issue...

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.