452afbf2ff
These allow for a given block to be wrapped in helper methods or metadata and allow for more control over the current container and method before the code is run.
169 lines
3.7 KiB
JavaScript
169 lines
3.7 KiB
JavaScript
/*global define */
|
|
import {isArray} from '../utils';
|
|
|
|
let SourceNode;
|
|
|
|
try {
|
|
/* istanbul ignore next */
|
|
if (typeof define !== 'function' || !define.amd) {
|
|
// We don't support this in AMD environments. For these environments, we asusme that
|
|
// they are running on the browser and thus have no need for the source-map library.
|
|
let SourceMap = require('source-map');
|
|
SourceNode = SourceMap.SourceNode;
|
|
}
|
|
} catch (err) {
|
|
/* NOP */
|
|
}
|
|
|
|
/* istanbul ignore if: tested but not covered in istanbul due to dist build */
|
|
if (!SourceNode) {
|
|
SourceNode = function(line, column, srcFile, chunks) {
|
|
this.src = '';
|
|
if (chunks) {
|
|
this.add(chunks);
|
|
}
|
|
};
|
|
/* istanbul ignore next */
|
|
SourceNode.prototype = {
|
|
add: function(chunks) {
|
|
if (isArray(chunks)) {
|
|
chunks = chunks.join('');
|
|
}
|
|
this.src += chunks;
|
|
},
|
|
prepend: function(chunks) {
|
|
if (isArray(chunks)) {
|
|
chunks = chunks.join('');
|
|
}
|
|
this.src = chunks + this.src;
|
|
},
|
|
toStringWithSourceMap: function() {
|
|
return {code: this.toString()};
|
|
},
|
|
toString: function() {
|
|
return this.src;
|
|
}
|
|
};
|
|
}
|
|
|
|
|
|
function castChunk(chunk, codeGen, loc) {
|
|
if (isArray(chunk)) {
|
|
let ret = [];
|
|
|
|
for (let i = 0, len = chunk.length; i < len; i++) {
|
|
ret.push(codeGen.wrap(chunk[i], loc));
|
|
}
|
|
return ret;
|
|
} else if (typeof chunk === 'boolean' || typeof chunk === 'number') {
|
|
// Handle primitives that the SourceNode will throw up on
|
|
return chunk + '';
|
|
}
|
|
return chunk;
|
|
}
|
|
|
|
|
|
function CodeGen(srcFile) {
|
|
this.srcFile = srcFile;
|
|
this.source = [];
|
|
}
|
|
|
|
CodeGen.prototype = {
|
|
isEmpty() {
|
|
return !this.source.length;
|
|
},
|
|
prepend: function(source, loc) {
|
|
this.source.unshift(this.wrap(source, loc));
|
|
},
|
|
push: function(source, loc) {
|
|
this.source.push(this.wrap(source, loc));
|
|
},
|
|
|
|
merge: function() {
|
|
let source = this.empty();
|
|
this.each(function(line) {
|
|
source.add([' ', line, '\n']);
|
|
});
|
|
return source;
|
|
},
|
|
|
|
each: function(iter) {
|
|
for (let i = 0, len = this.source.length; i < len; i++) {
|
|
iter(this.source[i]);
|
|
}
|
|
},
|
|
|
|
empty: function() {
|
|
let loc = this.currentLocation || {start: {}};
|
|
return new SourceNode(loc.start.line, loc.start.column, this.srcFile);
|
|
},
|
|
wrap: function(chunk, loc = this.currentLocation || {start: {}}) {
|
|
if (chunk instanceof SourceNode) {
|
|
return chunk;
|
|
}
|
|
|
|
chunk = castChunk(chunk, this, loc);
|
|
|
|
return new SourceNode(loc.start.line, loc.start.column, this.srcFile, chunk);
|
|
},
|
|
|
|
functionCall: function(fn, type, params) {
|
|
params = this.generateList(params);
|
|
return this.wrap([fn, type ? '.' + type + '(' : '(', params, ')']);
|
|
},
|
|
|
|
quotedString: function(str) {
|
|
return '"' + (str + '')
|
|
.replace(/\\/g, '\\\\')
|
|
.replace(/"/g, '\\"')
|
|
.replace(/\n/g, '\\n')
|
|
.replace(/\r/g, '\\r')
|
|
.replace(/\u2028/g, '\\u2028') // Per Ecma-262 7.3 + 7.8.4
|
|
.replace(/\u2029/g, '\\u2029') + '"';
|
|
},
|
|
|
|
objectLiteral: function(obj) {
|
|
let pairs = [];
|
|
|
|
for (let key in obj) {
|
|
if (obj.hasOwnProperty(key)) {
|
|
let value = castChunk(obj[key], this);
|
|
if (value !== 'undefined') {
|
|
pairs.push([this.quotedString(key), ':', value]);
|
|
}
|
|
}
|
|
}
|
|
|
|
let ret = this.generateList(pairs);
|
|
ret.prepend('{');
|
|
ret.add('}');
|
|
return ret;
|
|
},
|
|
|
|
|
|
generateList: function(entries) {
|
|
let ret = this.empty();
|
|
|
|
for (let i = 0, len = entries.length; i < len; i++) {
|
|
if (i) {
|
|
ret.add(',');
|
|
}
|
|
|
|
ret.add(castChunk(entries[i], this));
|
|
}
|
|
|
|
return ret;
|
|
},
|
|
|
|
generateArray: function(entries) {
|
|
let ret = this.generateList(entries);
|
|
ret.prepend('[');
|
|
ret.add(']');
|
|
|
|
return ret;
|
|
}
|
|
};
|
|
|
|
export default CodeGen;
|
|
|