cst
Version:
JavaScript CST Implementation
310 lines (261 loc) • 11 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
var _keys = require('babel-runtime/core-js/object/keys');
var _keys2 = _interopRequireDefault(_keys);
var _toConsumableArray2 = require('babel-runtime/helpers/toConsumableArray');
var _toConsumableArray3 = _interopRequireDefault(_toConsumableArray2);
var _getIterator2 = require('babel-runtime/core-js/get-iterator');
var _getIterator3 = _interopRequireDefault(_getIterator2);
var _extends2 = require('babel-runtime/helpers/extends');
var _extends3 = _interopRequireDefault(_extends2);
var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck');
var _classCallCheck3 = _interopRequireDefault(_classCallCheck2);
var _createClass2 = require('babel-runtime/helpers/createClass');
var _createClass3 = _interopRequireDefault(_createClass2);
var _babylon = require('babylon');
var _elementTree = require('./elementTree');
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
/**
* @typedef {Object} CSTParserOptions
* @property {String} sourceType Type of parsed code: "module" or "script".
* @property {Boolean} allowReturnOutsideFunction
* @property {Boolean} allowImportExportEverywhere
* @property {Boolean} allowSuperOutsideMethod
* @property {CSTParserExperimentalFeatureOptions} experimentalFeatures
* @property {CSTParserLanguageExtensionsOptions} languageExtensions
*/
/**
* @typedef {Object} CSTParserLanguageExtensionsOptions
* @property {Boolean} jsx
* @property {Boolean} flow
*/
/**
* @typedef {Object} CSTParserExperimentalFeatureOptions
* @property {Boolean} 'flow'
* @property {Boolean} 'jsx'
* @property {Boolean} 'asyncFunctions'
* @property {Boolean} 'asyncGenerators'
* @property {Boolean} 'classConstructorCall'
* @property {Boolean} 'classProperties'
* @property {Boolean} 'decorators'
* @property {Boolean} 'doExpressions'
* @property {Boolean} 'exponentiationOperator'
* @property {Boolean} 'exportExtensions'
* @property {Boolean} 'functionBind'
* @property {Boolean} 'objectRestSpread'
* @property {Boolean} 'trailingFunctionCommas
*/
// https://developer.apple.com/library/watchos/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UIAutomation.html
var DIRECTIVE_APPLE_INSTRUMENTATION = {
type: 'AppleInstrumentationDirective',
regexp: /^#([^\n]+)/gm
};
// https://www.chromium.org/developers/web-development-style-guide
var DIRECTIVE_GRIT = {
type: 'GritDirective',
regexp: /^\s*<(\/?\s*(?:if|include)(?!\w)[^]*?)>/gim
};
// checking for the options passed to the babel parse method
/**
* CST Parser.
*/
var Parser = function () {
/**
* @param {CSTParserOptions} options
*/
function Parser(options) {
(0, _classCallCheck3.default)(this, Parser);
this._options = {
sourceType: 'module',
strictMode: true,
experimentalFeatures: {
'flow': true,
'jsx': true,
'asyncFunctions': true,
'asyncGenerators': true,
'classConstructorCall': true,
'classProperties': true,
'decorators': true,
'doExpressions': true,
'exponentiationOperator': true,
'exportExtensions': true,
'functionBind': true,
'objectRestSpread': true,
'trailingFunctionCommas': true
},
languageExtensions: {
jsx: true,
flow: true
},
plugins: []
};
if (options) {
this.setOptions(options);
}
}
(0, _createClass3.default)(Parser, [{
key: 'getOptions',
/**
* @returns {CSTParserOptions}
*/
value: function getOptions() {
return this._options;
}
/**
* @param {CSTParserOptions} newOptions
*/
}, {
key: 'setOptions',
value: function setOptions(newOptions) {
var currentOptions = this._options;
var currentExperimentalFeatures = currentOptions.experimentalFeatures;
var currentLanguageExtensions = currentOptions.languageExtensions;
var newExperimentalFeatures = newOptions.experimentalFeatures;
var newLanguageExtensions = newOptions.languageExtensions;
this._options = (0, _extends3.default)({}, currentOptions, newOptions, {
experimentalFeatures: (0, _extends3.default)({}, currentExperimentalFeatures, newExperimentalFeatures),
languageExtensions: (0, _extends3.default)({}, currentLanguageExtensions, newLanguageExtensions)
});
}
}, {
key: 'parse',
value: function parse(code) {
var ast = this._parseAst(code);
var tokens = this._processTokens(ast, code);
var program = (0, _elementTree.buildElementTree)(ast, tokens);
var programPlugins = {};
var plugins = this._options.plugins;
var _iteratorNormalCompletion = true;
var _didIteratorError = false;
var _iteratorError = undefined;
try {
for (var _iterator = (0, _getIterator3.default)(plugins), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var plugin = _step.value;
var api = plugin.createApiForProgram(program);
if (api) {
var pluginName = plugin.getPluginName();
if (pluginName in programPlugins) {
throw new Error('Plugin "' + pluginName + '" was already registered.');
} else {
programPlugins[pluginName] = api;
}
}
}
} catch (err) {
_didIteratorError = true;
_iteratorError = err;
} finally {
try {
if (!_iteratorNormalCompletion && _iterator.return) {
_iterator.return();
}
} finally {
if (_didIteratorError) {
throw _iteratorError;
}
}
}
program._acceptPlugins(programPlugins);
return program;
}
}, {
key: '_parseAst',
value: function _parseAst(code) {
var options = this._options;
var languageExtensions = options.languageExtensions;
var directiveInstances = {};
var hasDirectives = false;
var directiveTypes = [];
if (languageExtensions.appleInstrumentationDirectives) {
directiveTypes.push(DIRECTIVE_APPLE_INSTRUMENTATION);
}
if (languageExtensions.gritDirectives) {
directiveTypes.push(DIRECTIVE_GRIT);
}
var _iteratorNormalCompletion2 = true;
var _didIteratorError2 = false;
var _iteratorError2 = undefined;
try {
var _loop = function _loop() {
var directive = _step2.value;
code = code.replace(directive.regexp, function (str, value, pos) {
hasDirectives = true;
directiveInstances[pos] = {
type: directive.type, value: value
};
// Cut 4 characters to save correct line/column info for surrounding code
return '/*' + str.slice(4) + '*/';
});
};
for (var _iterator2 = (0, _getIterator3.default)(directiveTypes), _step2; !(_iteratorNormalCompletion2 = (_step2 = _iterator2.next()).done); _iteratorNormalCompletion2 = true) {
_loop();
}
} catch (err) {
_didIteratorError2 = true;
_iteratorError2 = err;
} finally {
try {
if (!_iteratorNormalCompletion2 && _iterator2.return) {
_iterator2.return();
}
} finally {
if (_didIteratorError2) {
throw _iteratorError2;
}
}
}
var ast = (0, _babylon.parse)(code, {
sourceType: options.sourceType,
strictMode: options.strictMode,
allowImportExportEverywhere: options.allowImportExportEverywhere,
allowReturnOutsideFunction: options.allowReturnOutsideFunction,
allowSuperOutsideMethod: options.allowSuperOutsideMethod,
plugins: [].concat((0, _toConsumableArray3.default)((0, _keys2.default)(options.experimentalFeatures)), (0, _toConsumableArray3.default)((0, _keys2.default)(options.languageExtensions)))
});
var program = ast.program;
program.tokens = ast.tokens;
if (hasDirectives) {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = (0, _getIterator3.default)(program.tokens), _step3; !(_iteratorNormalCompletion3 = (_step3 = _iterator3.next()).done); _iteratorNormalCompletion3 = true) {
var token = _step3.value;
var directiveInstance = directiveInstances[token.start];
if (directiveInstances[token.start]) {
token.type = directiveInstance.type;
token.value = directiveInstance.value;
}
}
} catch (err) {
_didIteratorError3 = true;
_iteratorError3 = err;
} finally {
try {
if (!_iteratorNormalCompletion3 && _iterator3.return) {
_iterator3.return();
}
} finally {
if (_didIteratorError3) {
throw _iteratorError3;
}
}
}
}
if (code.substr(0, 2) === '#!') {
program.tokens[0].type = 'Hashbang';
}
return program;
}
}, {
key: '_processTokens',
value: function _processTokens(ast, code) {
return (0, _elementTree.buildTokenList)(ast.tokens, code);
}
}]);
return Parser;
}();
exports.default = Parser;
//# sourceMappingURL=Parser.js.map