react-native/website/jsdocs/traverseFlat.js
Kevin Lacker 857bae4ea3 Replace the deprecated esprima-fb parser with flow-parser, on the RN website
Summary:
(I changed a ton from when I previously submitted this PR so please take another look if you already did.)

PROBLEM: the no-longer-maintained `esprima-fb` parser does not support class properties, leading our website docgen to die if we use class properties, which we're gonna do real soon now
SOLUTION: use `flow-parser` instead, which the flow team is maintaining including all the fancy-pants ES? stuff that FB uses internally.

This removes the `esprima-fb` parser from jsdocs and replaces it with `flow-parser`. It's almost the same, I checked by diffing all the parser json output and it only had a few irrelevant differences. I had to add a file of constants so that we could remove esprima-fb altogether, too.

This also adds a couple unit tests, so that we can test that jsDocs works programmatically. They don't run if you run the regular RN tests, you have to run `npm test` from the `/website/` subdirectory.
Closes https://github.com/facebook/react-native/pull/9890

Differential Revision: D3865629

Pulled By: bestander

fbshipit-source-id: 8f561b78ca4a02f3f7b45e55904ec2fa911e3bb6
2016-09-14 14:28:44 -07:00

105 lines
2.9 KiB
JavaScript

/**
* Copyright (c) 2015-present, Facebook, Inc.
* All rights reserved.
*
* This source code is licensed under the BSD-style license found in the
* LICENSE file in the root directory of this source tree. An additional grant
* of patent rights can be found in the PATENTS file in the same directory.
*/
/*global exports:true*/
/*jslint node:true*/
'use strict';
var Syntax = require('./syntax');
/**
* Executes visitor on the object and its children (recursively).
* While traversing the tree, a scope chain is built and passed to the visitor.
*
* If the visitor returns false, the object's children are not traversed.
*
* @param {object} object
* @param {function} visitor
* @param {?array} scopeChain
*/
function traverse(object, visitor, scopeChain) {
scopeChain = scopeChain || [{}];
var scope = scopeChain[0];
switch (object.type) {
case Syntax.VariableDeclaration:
object.declarations.forEach(function(decl) {
scope[decl.id.name] = decl.init;
});
break;
case Syntax.ClassDeclaration:
scope[object.id.name] = object;
break;
case Syntax.FunctionDeclaration:
// A function declaration creates a symbol in the current scope
scope[object.id.name] = object;
/* falls through */
case Syntax.FunctionExpression:
case Syntax.Program:
scopeChain = [{}].concat(scopeChain);
break;
}
if (object.type === Syntax.FunctionExpression ||
object.type === Syntax.FunctionDeclaration) {
// add parameters to the new scope
object.params.forEach(function(param) {
// since the value of the parameters are unknown during parsing time
// we set the value to `undefined`.
scopeChain[0][param.name] = undefined;
});
}
if (object.type) {
if (visitor.call(null, object, scopeChain) === false) {
return;
}
}
for (var key in object) {
if (object.hasOwnProperty(key)) {
var child = object[key];
if (typeof child === 'object' && child !== null) {
traverse(child, visitor, scopeChain);
}
}
}
}
/**
* Executes visitor on the object and its children, but only traverses into
* children which can be statically analyzed and don't depend on runtime
* information.
*
* @param {object} object
* @param {function} visitor
* @param {?array} scopeChain
*/
function traverseFlat(object, visitor, scopeChain) {
traverse(object, function(node, scopeChain) {
switch (node.type) {
case Syntax.FunctionDeclaration:
case Syntax.FunctionExpression:
case Syntax.IfStatement:
case Syntax.WithStatement:
case Syntax.SwitchStatement:
case Syntax.TryStatement:
case Syntax.WhileStatement:
case Syntax.DoWhileStatement:
case Syntax.ForStatement:
case Syntax.ForInStatement:
return false;
}
return visitor(node, scopeChain);
}, scopeChain);
}
module.exports = traverseFlat;