172 lines
3.8 KiB
Plaintext
172 lines
3.8 KiB
Plaintext
/* 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 = [];
|
|
|
|
Object.keys(obj).forEach(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;
|