cst
Version:
JavaScript CST Implementation
296 lines (253 loc) • 10.9 kB
JavaScript
/**
* @typedef {Object} CSTParserOptions
* @property {String} sourceType Type of parsed code: "module" or "script".
* @property {Boolean} strictMode
* @property {Boolean} allowHashBang
* @property {Number} ecmaVersion
* @property {CSTParserExperimentalFeatureOptions} experimentalFeatures
* @property {CSTParserLanguageExtensionsOptions} languageExtensions
*/
/**
* @typedef {Object} CSTParserLanguageExtensionsOptions
* @property {Boolean} jsx
* @property {Boolean} flow
*/
/**
* @typedef {Object} CSTParserExperimentalFeatureOptions
* @property {Boolean} 'es7.asyncFunctions'
* @property {Boolean} 'es7.classProperties'
* @property {Boolean} 'es7.comprehensions'
* @property {Boolean} 'es7.decorators'
* @property {Boolean} 'es7.doExpressions'
* @property {Boolean} 'es7.exponentiationOperator'
* @property {Boolean} 'es7.exportExtensions'
* @property {Boolean} 'es7.functionBind'
* @property {Boolean} 'es7.objectRestSpread'
* @property {Boolean} 'es7.trailingFunctionCommas'
*/
// https://developer.apple.com/library/watchos/documentation/DeveloperTools/Conceptual/InstrumentsUserGuide/UIAutomation.html
;
Object.defineProperty(exports, '__esModule', {
value: true
});
var _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; };
var _createClass = (function () { function defineProperties(target, props) { for (var i = 0; i < props.length; i++) { var descriptor = props[i]; descriptor.enumerable = descriptor.enumerable || false; descriptor.configurable = true; if ('value' in descriptor) descriptor.writable = true; Object.defineProperty(target, descriptor.key, descriptor); } } return function (Constructor, protoProps, staticProps) { if (protoProps) defineProperties(Constructor.prototype, protoProps); if (staticProps) defineProperties(Constructor, staticProps); return Constructor; }; })();
function _classCallCheck(instance, Constructor) { if (!(instance instanceof Constructor)) { throw new TypeError('Cannot call a class as a function'); } }
var _babylon = require('babylon');
var _elementTree = require('./elementTree');
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) {
_classCallCheck(this, Parser);
this._options = {
sourceType: 'module',
strictMode: true,
allowHashBang: true,
ecmaVersion: Infinity,
experimentalFeatures: {
'es7.asyncFunctions': true,
'es7.classProperties': true,
'es7.comprehensions': true,
'es7.decorators': true,
'es7.doExpressions': true,
'es7.exponentiationOperator': true,
'es7.exportExtensions': true,
'es7.functionBind': true,
'es7.objectRestSpread': true,
'es7.trailingFunctionCommas': true
},
languageExtensions: {
jsx: true,
flow: true
},
plugins: []
};
if (options) {
this.setOptions(options);
}
}
_createClass(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 = _extends({}, currentOptions, newOptions, {
experimentalFeatures: _extends({}, currentExperimentalFeatures, newExperimentalFeatures),
languageExtensions: _extends({}, 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 = plugins[Symbol.iterator](), _step; !(_iteratorNormalCompletion = (_step = _iterator.next()).done); _iteratorNormalCompletion = true) {
var plugin = _step.value;
var api = plugin.createApiForProgram(program);
if (api) {
if (plugin.pluginName in programPlugins) {
throw new Error('Plugin "' + plugin.pluginName + '" was already registered.');
} else {
programPlugins[plugin.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 () {
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 = directiveTypes[Symbol.iterator](), _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,
ecmaVersion: options.ecmaVersion,
allowHashBang: options.allowHashBang,
features: options.experimentalFeatures,
plugins: {
jsx: languageExtensions.jsx,
flow: languageExtensions.flow
}
});
var program = ast.program;
program.tokens = ast.tokens;
if (hasDirectives) {
var _iteratorNormalCompletion3 = true;
var _didIteratorError3 = false;
var _iteratorError3 = undefined;
try {
for (var _iterator3 = program.tokens[Symbol.iterator](), _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 (options.allowHashBang) {
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;
module.exports = exports['default'];
// allowReturnOutsideFunction: boolean,
// allowImportExportEverywhere: boolean,