Skip to content

Commit

Permalink
Merge 4e6d3db into 2fbffe4
Browse files Browse the repository at this point in the history
  • Loading branch information
fossamagna committed Sep 5, 2020
2 parents 2fbffe4 + 4e6d3db commit 8b50bda
Show file tree
Hide file tree
Showing 7 changed files with 208 additions and 33 deletions.
1 change: 1 addition & 0 deletions .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
module.exports = {
"env": {
"es6": true,
"node": true,
"commonjs": true
},
Expand Down
51 changes: 44 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
# gas-entry-generator [![NPM version][npm-image]][npm-url]  [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url]  [![Coverage percentage][coveralls-image]][coveralls-url] [![Greenkeeper badge](https://badges.greenkeeper.io/fossamagna/gas-entry-generator.svg)](https://greenkeeper.io/)
# gas-entry-generator [![NPM version][npm-image]][npm-url]  [![Build Status][travis-image]][travis-url] [![Dependency Status][daviddm-image]][daviddm-url]  [![Coverage percentage][coveralls-image]][coveralls-url]

Top level function generator for Google Apps Script.

Expand Down Expand Up @@ -26,15 +26,15 @@ global.foo = function () {

generate.js:
```js
var fs = require('fs');
var gasEntryGenerator = require('gas-entry-generator');
const fs = require('fs');
const { generate } = require('gas-entry-generator');

var fooSource = fs.readFileSync('foo.js', {encoding: 'utf8'});
var options = {
const fooSource = fs.readFileSync('foo.js', {encoding: 'utf8'});
const options = {
comment: true
};
var entryFunction = gasEntryGenerator(fooSource, options);
console.log(entryFunction);
const output = generate(fooSource, options);
console.log(output.entryPointFunctions);
```

Console output:
Expand All @@ -51,6 +51,43 @@ Execute to generate function as entry point.
$ node generate.js
```

## geranate global assignment expressions from exports.*

foo.ts:
```ts
/**
* comment for foo function.
*/
exports.foo = () => 'bar';
```

generate.js:
```js
const fs = require('fs');
const { generate } = require('gas-entry-generator');

const fooSource = fs.readFileSync('foo.js', {encoding: 'utf8'});
const options = {
comment: true,
autoGlobalExports: true // Enable to detect exports.* to generate entry point functions.
};
const output = generate(fooSource, options);
console.log(output.entryPointFunctions);
console.log('-----');
console.log(output.globalAssignments);
```

Console output:
```
/**
* comment for foo function.
*/
function foo() {
}
-----
global.foo = exports.foo;
```

[npm-image]: https://badge.fury.io/js/gas-entry-generator.svg
[npm-url]: https://npmjs.org/package/gas-entry-generator
[travis-image]: https://travis-ci.org/fossamagna/gas-entry-generator.svg?branch=master
Expand Down
131 changes: 113 additions & 18 deletions index.js
Original file line number Diff line number Diff line change
@@ -1,18 +1,18 @@
'use strict';

var esprima = require('esprima');
var estraverse = require('estraverse');
var escodegen = require('escodegen');
const esprima = require('esprima');
const estraverse = require('estraverse');
const escodegen = require('escodegen');

function createBaseAST() {
var ast = {};
const ast = {};
ast.type = 'Program';
ast.body = [];
return ast;
}

function createStubFunctionASTNode(functionName, leadingComments, params) {
var node = {
const node = {
type: 'FunctionDeclaration',
id: {
type: 'Identifier',
Expand All @@ -36,26 +36,41 @@ function createStubFunctionASTNode(functionName, leadingComments, params) {
return node;
}

function _generateStubs(data, options) {
var ast = esprima.parseScript(data, { attachComment: options.comment });
var stubs = [];
var functionName;
function _generateStubs(ast, options) {
const autoGlobalExports = options.autoGlobalExports;
const stubs = [];
estraverse.traverse(ast, {
leave: function (node) {
if (node.type === 'ExpressionStatement'
&& isGlobalAssignmentExpression(node.expression)) {
functionName = node.expression.left.property.name;
const functionName = node.expression.left.property.name;
stubs.push(createStubFunctionASTNode(functionName, node.leadingComments, node.expression.right.params));
} else if (node.type === 'ExpressionStatement'
&& node.expression.type === 'SequenceExpression') {
node.expression.expressions.forEach(function (expression) {
if (isGlobalAssignmentExpression(expression)) {
functionName = expression.left.property.name;
const functionName = expression.left.property.name;
stubs.push(createStubFunctionASTNode(functionName, expression.leadingComments ?
expression.leadingComments : node.leadingComments, expression.right.params));
}
});
}
if (autoGlobalExports) {
if (node.type === 'ExpressionStatement'
&& isExportsAssignmentExpression(node.expression)) {
const functionName = node.expression.left.property.name;
stubs.push(createStubFunctionASTNode(functionName, node.leadingComments, node.expression.right.params));
} else if (node.type === 'ExpressionStatement'
&& node.expression.type === 'SequenceExpression') {
node.expression.expressions.forEach(function (expression) {
if (isExportsAssignmentExpression(expression)) {
const functionName = expression.left.property.name;
stubs.push(createStubFunctionASTNode(functionName, expression.leadingComments ?
expression.leadingComments : node.leadingComments, expression.right.params));
}
});
}
}
}
});

Expand All @@ -70,15 +85,95 @@ function isGlobalAssignmentExpression(node) {
&& node.left.object.name === 'global'
}

function generateStubs(source, options) {
options = options || {comment: false};
var comment = !!options.comment;
var baseAST = createBaseAST();
var stubs = _generateStubs(source, options);
function isExportsAssignmentExpression(node) {
return node.type === 'AssignmentExpression'
&& node.operator === '='
&& node.left.type === 'MemberExpression'
&& node.left.object.type === 'Identifier'
&& node.left.object.name === 'exports'
}

function generateStubs(ast, options) {
const baseAST = createBaseAST();
const stubs = _generateStubs(ast, options);
stubs.forEach(function (stub) {
baseAST.body.push(stub);
});
return escodegen.generate(baseAST, { comment: comment });
return escodegen.generate(baseAST, { comment: !!options.comment });
}

function generateGlobalAssignments(ast) {
const stubs = [];
estraverse.traverse(ast, {
leave: (node) => {
if (node.type === 'ExpressionStatement'
&& isExportsAssignmentExpression(node.expression)) {
const functionName = node.expression.left.property.name;
stubs.push(createGlobalAssignmentASTNode(functionName));
} else if (node.type === 'ExpressionStatement'
&& node.expression.type === 'SequenceExpression') {
node.expression.expressions.forEach(function (expression) {
if (isExportsAssignmentExpression(expression)) {
const functionName = expression.left.property.name;
stubs.push(createGlobalAssignmentASTNode(functionName));
}
});
}
}
});
const baseAST = createBaseAST();
stubs.forEach(function (stub) {
baseAST.body.push(stub);
});
return escodegen.generate(baseAST);
}

function createGlobalAssignmentASTNode(functionName) {
const node = {
type: "ExpressionStatement",
expression: {
type: "AssignmentExpression",
operator: "=",
left: {
type: "MemberExpression",
computed: false,
object: {
type: "Identifier",
name: "global"
},
property: {
type: "Identifier",
name: functionName
}
},
right: {
type: "MemberExpression",
computed: false,
object: {
type: "Identifier",
name: "exports"
},
property: {
type: "Identifier",
name: functionName
}
}
}
};
return node;
}

// exports.generateEntryPointFunctions = generateStubs;

// exports.generateGlobalAssignments = generateGlobalAssignments;

exports.generate = function(source, options = { comment: false, autoGlobalExports: false }){
const ast = esprima.parseScript(source, { attachComment: options.comment });
const functions = generateStubs(ast, options);
const globalAssignments = options.autoGlobalExports ? generateGlobalAssignments(ast, options) : undefined;
return {
entryPointFunctions : functions,
globalAssignments
};
}

module.exports = generateStubs;
14 changes: 14 additions & 0 deletions test/fixtures/exports-expected.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* This is foo.
*/
function foo() {
}
/**
* This is boo.
*/
function boo() {
}
function test() {
}
function X() {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
global.foo = exports.foo;
global.boo = exports.boo;
global.test = exports.test;
global.X = exports.X;
14 changes: 14 additions & 0 deletions test/fixtures/exports-source.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
/**
* This is foo.
*/
exports.foo = function() {}

/**
* This is boo.
*/
exports.boo = () => {};

function test() {
};
var X = 'x';
exports.test = test, exports.X = X;
26 changes: 18 additions & 8 deletions test/index.test.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,22 @@
var test = require('tap').test;
var fs = require('fs');
const test = require('tap').test;
const fs = require('fs');
const { generate } = require('../');

var gasEntryGenerator = require('../');
test('generate function generate entry functions and global assignments from exports.*', function(t) {
const source = fs.readFileSync(__dirname + '/fixtures/exports-source.js', {encoding: 'utf8'});
const expected = fs.readFileSync(__dirname + '/fixtures/exports-expected.js', {encoding: 'utf8'});
const expectedGlobalAssignments = fs.readFileSync(__dirname + '/fixtures/exports-generated-global-assignments-expected.js', {encoding: 'utf8'});
const output = generate(source, { comment: true, autoGlobalExports: true });
t.equal(output.entryPointFunctions, expected, 'actual output will match expected');
t.equal(output.globalAssignments, expectedGlobalAssignments, 'actual output will match expected');
t.end();
});

test('gas-entry-generator', function(t) {
var source = fs.readFileSync(__dirname + '/fixtures/source.js', {encoding: 'utf8'});
var expected = fs.readFileSync(__dirname + '/fixtures/expected.js', {encoding: 'utf8'});
var entryFunctions = gasEntryGenerator(source, {comment: true});
t.equal(entryFunctions.toString(), expected.toString(), 'actual output will match expected');
test('generate function generate entry functions from global assignments', function(t) {
const source = fs.readFileSync(__dirname + '/fixtures/source.js', {encoding: 'utf8'});
const expected = fs.readFileSync(__dirname + '/fixtures/expected.js', {encoding: 'utf8'});
const output = generate(source, { comment: true });
t.equal(output.entryPointFunctions, expected, 'actual output will match expected');
t.equal(output.globalAssignments, undefined, 'actual output will match expected');
t.end();
});

0 comments on commit 8b50bda

Please sign in to comment.