core.js 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185
  1. /*
  2. * Copyright (c) 2015-present, Facebook, Inc.
  3. * All rights reserved.
  4. *
  5. * This source code is licensed under the BSD-style license found in the
  6. * LICENSE file in the root directory of this source tree. An additional grant
  7. * of patent rights can be found in the PATENTS file in the same directory.
  8. *
  9. */
  10. 'use strict';
  11. const Collection = require('./Collection');
  12. const collections = require('./collections');
  13. const getParser = require('./getParser');
  14. const matchNode = require('./matchNode');
  15. const recast = require('recast');
  16. const template = require('./template');
  17. const Node = recast.types.namedTypes.Node;
  18. const NodePath = recast.types.NodePath;
  19. // Register all built-in collections
  20. for (var name in collections) {
  21. collections[name].register();
  22. }
  23. /**
  24. * Main entry point to the tool. The function accepts multiple different kinds
  25. * of arguments as a convenience. In particular the function accepts either
  26. *
  27. * - a string containing source code
  28. * The string is parsed with Recast
  29. * - a single AST node
  30. * - a single node path
  31. * - an array of nodes
  32. * - an array of node paths
  33. *
  34. * @exports jscodeshift
  35. * @param {Node|NodePath|Array|string} source
  36. * @param {Object} options Options to pass to Recast when passing source code
  37. * @return {Collection}
  38. */
  39. function core(source, options) {
  40. return typeof source === 'string' ?
  41. fromSource(source, options) :
  42. fromAST(source);
  43. }
  44. /**
  45. * Returns a collection from a node, node path, array of nodes or array of node
  46. * paths.
  47. *
  48. * @ignore
  49. * @param {Node|NodePath|Array} source
  50. * @return {Collection}
  51. */
  52. function fromAST(ast) {
  53. if (Array.isArray(ast)) {
  54. if (ast[0] instanceof NodePath || ast.length === 0) {
  55. return Collection.fromPaths(ast);
  56. } else if (Node.check(ast[0])) {
  57. return Collection.fromNodes(ast);
  58. }
  59. } else {
  60. if (ast instanceof NodePath) {
  61. return Collection.fromPaths([ast]);
  62. } else if (Node.check(ast)) {
  63. return Collection.fromNodes([ast]);
  64. }
  65. }
  66. throw new TypeError(
  67. 'Received an unexpected value ' + Object.prototype.toString.call(ast)
  68. );
  69. }
  70. function fromSource(source, options) {
  71. if (!options) {
  72. options = {};
  73. }
  74. if (!options.parser) {
  75. options.parser = getParser();
  76. }
  77. return fromAST(recast.parse(source, options));
  78. }
  79. /**
  80. * Utility function to match a node against a pattern.
  81. * @augments core
  82. * @static
  83. * @param {Node|NodePath|Object} path
  84. * @parma {Object} filter
  85. * @return boolean
  86. */
  87. function match(path, filter) {
  88. if (!(path instanceof NodePath)) {
  89. if (typeof path.get === 'function') {
  90. path = path.get();
  91. } else {
  92. path = {value: path};
  93. }
  94. }
  95. return matchNode(path.value, filter);
  96. }
  97. const plugins = [];
  98. /**
  99. * Utility function for registering plugins.
  100. *
  101. * Plugins are simple functions that are passed the core jscodeshift instance.
  102. * They should extend jscodeshift by calling `registerMethods`, etc.
  103. * This method guards against repeated registrations (the plugin callback will only be called once).
  104. *
  105. * @augments core
  106. * @static
  107. * @param {Function} plugin
  108. */
  109. function use(plugin) {
  110. if (plugins.indexOf(plugin) === -1) {
  111. plugins.push(plugin);
  112. plugin(core);
  113. }
  114. }
  115. /**
  116. * Returns a version of the core jscodeshift function "bound" to a specific
  117. * parser.
  118. *
  119. * @augments core
  120. * @static
  121. */
  122. function withParser(parser) {
  123. if (typeof parser === 'string') {
  124. parser = getParser(parser);
  125. }
  126. const newCore = function(source, options) {
  127. if (options && !options.parser) {
  128. options.parser = parser;
  129. } else {
  130. options = {parser};
  131. }
  132. return core(source, options);
  133. };
  134. return enrichCore(newCore, parser);
  135. }
  136. /**
  137. * The ast-types library
  138. * @external astTypes
  139. * @see {@link https://github.com/benjamn/ast-types}
  140. */
  141. function enrichCore(core, parser) {
  142. // add builders and types to the function for simple access
  143. Object.assign(core, recast.types.namedTypes);
  144. Object.assign(core, recast.types.builders);
  145. core.registerMethods = Collection.registerMethods;
  146. /**
  147. * @augments core
  148. * @type external:astTypes
  149. */
  150. core.types = recast.types;
  151. core.match = match;
  152. core.template = template(parser);
  153. // add mappings and filters to function
  154. core.filters = {};
  155. core.mappings = {};
  156. for (const name in collections) {
  157. if (collections[name].filters) {
  158. core.filters[name] = collections[name].filters;
  159. }
  160. if (collections[name].mappings) {
  161. core.mappings[name] = collections[name].mappings;
  162. }
  163. }
  164. core.use = use;
  165. core.withParser = withParser;
  166. return core;
  167. }
  168. module.exports = enrichCore(core, getParser());