core.js 4.4 KB

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