mirror of
https://github.com/status-im/react-native.git
synced 2025-02-03 05:03:42 +00:00
Update react-docgen and ignore pages with no header
This commit is contained in:
parent
022696c345
commit
472c287cd3
211
website/react-docgen/lib/ReactDocumentationParser.js
vendored
211
website/react-docgen/lib/ReactDocumentationParser.js
vendored
@ -13,201 +13,112 @@
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
/**
|
||||
* How this parser works:
|
||||
*
|
||||
* 1. For each given file path do:
|
||||
*
|
||||
* a. Find component definition
|
||||
* -. Find the rvalue module.exports assignment.
|
||||
* Otherwise inspect assignments to exports. If there are multiple
|
||||
* components that are exported, we don't continue with parsing the file.
|
||||
* -. If the previous step results in a variable name, resolve it.
|
||||
* -. Extract the object literal from the React.createClass call.
|
||||
*
|
||||
* b. Execute definition handlers (handlers working with the object
|
||||
* expression).
|
||||
*
|
||||
* c. For each property of the definition object, execute the registered
|
||||
* callbacks, if they are eligible for this property.
|
||||
*
|
||||
* 2. Return the aggregated results
|
||||
*/
|
||||
|
||||
type Handler = (documentation: Documentation, path: NodePath) => void;
|
||||
|
||||
var Documentation = require('./Documentation');
|
||||
|
||||
var expressionTo = require('./utils/expressionTo');
|
||||
var findExportedReactCreateClass =
|
||||
require('./strategies/findExportedReactCreateClassCall');
|
||||
var getPropertyName = require('./utils/getPropertyName');
|
||||
var isReactModuleName = require('./utils/isReactModuleName');
|
||||
var match = require('./utils/match');
|
||||
var resolveToValue = require('./utils/resolveToValue');
|
||||
var resolveToModule = require('./utils/resolveToModule');
|
||||
var recast = require('recast');
|
||||
var resolveToValue = require('./utils/resolveToValue');
|
||||
var n = recast.types.namedTypes;
|
||||
|
||||
function ignore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the statement is of form `foo = bar;`.
|
||||
*
|
||||
* @param {object} node
|
||||
* @return {bool}
|
||||
*/
|
||||
function isAssignmentStatement(node) {
|
||||
return match(node, {expression: {operator: '='}});
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the expression is of form `exports.foo = bar;` or
|
||||
* `modules.exports = foo;`.
|
||||
*
|
||||
* @param {object} node
|
||||
* @return {bool}
|
||||
*/
|
||||
function isExportsOrModuleExpression(path) {
|
||||
if (!n.AssignmentExpression.check(path.node) ||
|
||||
!n.MemberExpression.check(path.node.left)) {
|
||||
return false;
|
||||
}
|
||||
var exprArr = expressionTo.Array(path.get('left'));
|
||||
return (exprArr[0] === 'module' && exprArr[1] === 'exports') ||
|
||||
exprArr[0] == 'exports';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the expression is a function call of the form
|
||||
* `React.createClass(...)`.
|
||||
*
|
||||
* @param {object} node
|
||||
* @param {array} scopeChain
|
||||
* @return {bool}
|
||||
*/
|
||||
function isReactCreateClassCall(path) {
|
||||
if (!match(path.node, {callee: {property: {name: 'createClass'}}})) {
|
||||
return false;
|
||||
}
|
||||
var module = resolveToModule(path.get('callee', 'object'));
|
||||
return module && isReactModuleName(module);
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an AST, this function tries to find the object expression that is
|
||||
* passed to `React.createClass`, by resolving all references properly.
|
||||
*
|
||||
* @param {object} ast
|
||||
* @return {?object}
|
||||
*/
|
||||
function findComponentDefinition(ast) {
|
||||
var definition;
|
||||
|
||||
recast.visit(ast, {
|
||||
visitFunctionDeclaration: ignore,
|
||||
visitFunctionExpression: ignore,
|
||||
visitIfStatement: ignore,
|
||||
visitWithStatement: ignore,
|
||||
visitSwitchStatement: ignore,
|
||||
visitTryStatement: ignore,
|
||||
visitWhileStatement: ignore,
|
||||
visitDoWhileStatement: ignore,
|
||||
visitForStatement: ignore,
|
||||
visitForInStatement: ignore,
|
||||
visitAssignmentExpression: function(path) {
|
||||
// Ignore anything that is not `exports.X = ...;` or
|
||||
// `module.exports = ...;`
|
||||
if (!isExportsOrModuleExpression(path)) {
|
||||
return false;
|
||||
}
|
||||
// Resolve the value of the right hand side. It should resolve to a call
|
||||
// expression, something like React.createClass
|
||||
path = resolveToValue(path.get('right'));
|
||||
if (!isReactCreateClassCall(path)) {
|
||||
return false;
|
||||
}
|
||||
if (definition) { // If a file exports multiple components, ... complain!
|
||||
throw new Error(ReactDocumentationParser.ERROR_MULTIPLE_DEFINITIONS);
|
||||
}
|
||||
// We found React.createClass. Lets get cracking!
|
||||
definition = resolveToValue(path.get('arguments', 0));
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
|
||||
class ReactDocumentationParser {
|
||||
_componentHandlers: Array<Handler>;
|
||||
_propertyHandlers: Object<string, Handler>;
|
||||
_apiHandlers: Object<string, Handler>;
|
||||
|
||||
constructor() {
|
||||
this._componentHandlers = [];
|
||||
this._propertyHandlers = Object.create(null);
|
||||
this._apiHandlers = Object.create(null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handlers extract information from the component definition.
|
||||
* Handlers to extract information from the component definition.
|
||||
*
|
||||
* If "property" is not provided, the handler is passed the whole component
|
||||
* definition.
|
||||
*
|
||||
* NOTE: The component definition is currently expected to be represented as
|
||||
* an ObjectExpression (an object literal). This will likely change in the
|
||||
* future.
|
||||
*/
|
||||
addHandler(handler: Handler, property?: string): void {
|
||||
if (!property) {
|
||||
this._componentHandlers.push(handler);
|
||||
} else {
|
||||
if (!this._propertyHandlers[property]) {
|
||||
this._propertyHandlers[property] = [];
|
||||
if (!this._apiHandlers[property]) {
|
||||
this._apiHandlers[property] = [];
|
||||
}
|
||||
this._propertyHandlers[property].push(handler);
|
||||
this._apiHandlers[property].push(handler);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Takes JavaScript source code and returns an object with the information
|
||||
* extract from it.
|
||||
*
|
||||
* The second argument is strategy to find the AST node(s) of the component
|
||||
* definition(s) inside `source`.
|
||||
* It is a function that gets passed the program AST node of
|
||||
* the source as first argument, and a reference to recast as second argument.
|
||||
*
|
||||
* This allows you define your own strategy for finding component definitions.
|
||||
* By default it will look for the exported component created by
|
||||
* React.createClass. An error is thrown if multiple components are exported.
|
||||
*
|
||||
* NOTE: The component definition is currently expected to be represented as
|
||||
* an ObjectExpression (an object literal), no matter which strategy is
|
||||
* chosen. This will likely change in the future.
|
||||
*/
|
||||
parseSource(source: string): Object {
|
||||
var documentation = new Documentation();
|
||||
parseSource(
|
||||
source: string,
|
||||
componentDefinitionStrategy?:
|
||||
(program: ASTNode, recast: Object) => (Array<NodePath>|NodePath)
|
||||
): (Array<Object>|Object) {
|
||||
if (!componentDefinitionStrategy) {
|
||||
componentDefinitionStrategy = findExportedReactCreateClass;
|
||||
}
|
||||
var ast = recast.parse(source);
|
||||
// Find the component definition first. The return value should be
|
||||
// Find the component definitions first. The return value should be
|
||||
// an ObjectExpression.
|
||||
var componentDefinition = findComponentDefinition(ast.program);
|
||||
if (!componentDefinition) {
|
||||
var componentDefinition = componentDefinitionStrategy(ast.program, recast);
|
||||
var isArray = Array.isArray(componentDefinition);
|
||||
if (!componentDefinition || (isArray && componentDefinition.length === 0)) {
|
||||
throw new Error(ReactDocumentationParser.ERROR_MISSING_DEFINITION);
|
||||
}
|
||||
|
||||
// Execute all the handlers to extract the information
|
||||
this._executeHandlers(documentation, componentDefinition);
|
||||
|
||||
return documentation.toObject();
|
||||
return isArray ?
|
||||
this._executeHandlers(componentDefinition).map(
|
||||
documentation => documentation.toObject()
|
||||
) :
|
||||
this._executeHandlers([componentDefinition])[0].toObject();
|
||||
}
|
||||
|
||||
_executeHandlers(documentation, componentDefinition: NodePath) {
|
||||
componentDefinition.get('properties').each(propertyPath => {
|
||||
var name = getPropertyName(propertyPath);
|
||||
if (!this._propertyHandlers[name]) {
|
||||
return;
|
||||
}
|
||||
var propertyValuePath = propertyPath.get('value');
|
||||
this._propertyHandlers[name].forEach(
|
||||
handler => handler(documentation, propertyValuePath)
|
||||
_executeHandlers(componentDefinitions: Array<NodePath>): Array<Documenation> {
|
||||
return componentDefinitions.map(componentDefinition => {
|
||||
var documentation = new Documentation();
|
||||
componentDefinition.get('properties').each(propertyPath => {
|
||||
var name = getPropertyName(propertyPath);
|
||||
if (!this._apiHandlers[name]) {
|
||||
return;
|
||||
}
|
||||
var propertyValuePath = propertyPath.get('value');
|
||||
this._apiHandlers[name].forEach(
|
||||
handler => handler(documentation, propertyValuePath)
|
||||
);
|
||||
});
|
||||
|
||||
this._componentHandlers.forEach(
|
||||
handler => handler(documentation, componentDefinition)
|
||||
);
|
||||
return documentation;
|
||||
});
|
||||
|
||||
this._componentHandlers.forEach(
|
||||
handler => handler(documentation, componentDefinition)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
ReactDocumentationParser.ERROR_MISSING_DEFINITION =
|
||||
'No suitable component definition found.';
|
||||
|
||||
ReactDocumentationParser.ERROR_MULTIPLE_DEFINITIONS =
|
||||
'Multiple exported component definitions found.';
|
||||
|
||||
module.exports = ReactDocumentationParser;
|
||||
|
@ -10,109 +10,52 @@
|
||||
|
||||
"use strict";
|
||||
|
||||
require('mock-modules').autoMockOff();
|
||||
jest.autoMockOff();
|
||||
|
||||
describe('React documentation parser', function() {
|
||||
var ReactDocumentationParser;
|
||||
var parser;
|
||||
var recast;
|
||||
|
||||
beforeEach(function() {
|
||||
recast = require('recast');
|
||||
ReactDocumentationParser = require('../ReactDocumentationParser');
|
||||
parser = new ReactDocumentationParser();
|
||||
});
|
||||
|
||||
it('errors if component definition is not found', function() {
|
||||
var source = 'var React = require("React");';
|
||||
function pathFromSource(source) {
|
||||
return new recast.types.NodePath(
|
||||
recast.parse(source).program.body[0].expression
|
||||
);
|
||||
}
|
||||
|
||||
describe('parseSource', function() {
|
||||
|
||||
it('allows custom component definition resolvers', function() {
|
||||
var path = pathFromSource('({foo: "bar"})');
|
||||
var resolver = jest.genMockFunction().mockReturnValue(path);
|
||||
var handler = jest.genMockFunction();
|
||||
parser.addHandler(handler);
|
||||
parser.parseSource('', resolver);
|
||||
|
||||
expect(resolver).toBeCalled();
|
||||
expect(handler.mock.calls[0][1]).toBe(path);
|
||||
});
|
||||
|
||||
it('errors if component definition is not found', function() {
|
||||
var handler = jest.genMockFunction();
|
||||
expect(function() {
|
||||
parser.parseSource('', handler);
|
||||
}).toThrow(ReactDocumentationParser.ERROR_MISSING_DEFINITION);
|
||||
expect(handler).toBeCalled();
|
||||
|
||||
handler = jest.genMockFunction().mockReturnValue([]);
|
||||
expect(function() {
|
||||
parser.parseSource('', handler);
|
||||
}).toThrow(ReactDocumentationParser.ERROR_MISSING_DEFINITION);
|
||||
expect(handler).toBeCalled();
|
||||
});
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).toThrow(ReactDocumentationParser.ERROR_MISSING_DEFINITION);
|
||||
});
|
||||
|
||||
it('finds React.createClass', function() {
|
||||
var source = [
|
||||
'var React = require("React");',
|
||||
'var Component = React.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('finds React.createClass, independent of the var name', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var Component = R.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('does not process X.createClass of other modules', function() {
|
||||
var source = [
|
||||
'var R = require("NoReact");',
|
||||
'var Component = R.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).toThrow(ReactDocumentationParser.ERROR_MISSING_DEFINITION);
|
||||
});
|
||||
|
||||
it('finds assignments to exports', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var Component = R.createClass({});',
|
||||
'exports.foo = 42;',
|
||||
'exports.Component = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).not.toThrow();
|
||||
});
|
||||
|
||||
it('errors if multiple components are exported', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'exports.ComponentA = ComponentA;',
|
||||
'exports.ComponentB = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).toThrow(ReactDocumentationParser.ERROR_MULTIPLE_DEFINITIONS);
|
||||
});
|
||||
|
||||
it('accepts multiple definitions if only one is exported', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'exports.ComponentB = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).not.toThrow();
|
||||
|
||||
source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'module.exports = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parser.parseSource(source);
|
||||
}).not.toThrow();
|
||||
});
|
||||
});
|
||||
|
106
website/react-docgen/lib/strategies/__tests__/findAllReactCreateClassCalls-test.js
vendored
Normal file
106
website/react-docgen/lib/strategies/__tests__/findAllReactCreateClassCalls-test.js
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
jest.autoMockOff();
|
||||
|
||||
describe('React documentation parser', function() {
|
||||
var findAllReactCreateClassCalls;
|
||||
var recast;
|
||||
|
||||
function parse(source) {
|
||||
return findAllReactCreateClassCalls(
|
||||
recast.parse(source).program,
|
||||
recast
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
findAllReactCreateClassCalls = require('../findAllReactCreateClassCalls');
|
||||
recast = require('recast');
|
||||
});
|
||||
|
||||
|
||||
it('finds React.createClass', function() {
|
||||
var source = [
|
||||
'var React = require("React");',
|
||||
'var Component = React.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
var result = parse(source);
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBe(1);
|
||||
expect(result[0] instanceof recast.types.NodePath).toBe(true);
|
||||
expect(result[0].node.type).toBe('ObjectExpression');
|
||||
});
|
||||
|
||||
it('finds React.createClass, independent of the var name', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var Component = R.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
var result = parse(source);
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBe(1);
|
||||
});
|
||||
|
||||
it('does not process X.createClass of other modules', function() {
|
||||
var source = [
|
||||
'var R = require("NoReact");',
|
||||
'var Component = R.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
var result = parse(source);
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBe(0);
|
||||
});
|
||||
|
||||
it('finds assignments to exports', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var Component = R.createClass({});',
|
||||
'exports.foo = 42;',
|
||||
'exports.Component = Component;'
|
||||
].join('\n');
|
||||
|
||||
var result = parse(source);
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBe(1);
|
||||
});
|
||||
|
||||
it('accepts multiple definitions', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'exports.ComponentB = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
var result = parse(source);
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBe(2);
|
||||
|
||||
source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'module.exports = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
result = parse(source);
|
||||
expect(Array.isArray(result)).toBe(true);
|
||||
expect(result.length).toBe(2);
|
||||
});
|
||||
});
|
106
website/react-docgen/lib/strategies/__tests__/findExportedReactCreateClassCall-test.js
vendored
Normal file
106
website/react-docgen/lib/strategies/__tests__/findExportedReactCreateClassCall-test.js
vendored
Normal file
@ -0,0 +1,106 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
"use strict";
|
||||
|
||||
jest.autoMockOff();
|
||||
|
||||
describe('React documentation parser', function() {
|
||||
var findExportedReactCreateClass;
|
||||
var recast;
|
||||
|
||||
function parse(source) {
|
||||
return findExportedReactCreateClass(
|
||||
recast.parse(source).program,
|
||||
recast
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
findExportedReactCreateClass =
|
||||
require('../findExportedReactCreateClassCall');
|
||||
recast = require('recast');
|
||||
});
|
||||
|
||||
it('finds React.createClass', function() {
|
||||
var source = [
|
||||
'var React = require("React");',
|
||||
'var Component = React.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(parse(source)).toBeDefined();
|
||||
});
|
||||
|
||||
it('finds React.createClass, independent of the var name', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var Component = R.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(parse(source)).toBeDefined();
|
||||
});
|
||||
|
||||
it('does not process X.createClass of other modules', function() {
|
||||
var source = [
|
||||
'var R = require("NoReact");',
|
||||
'var Component = R.createClass({});',
|
||||
'module.exports = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(parse(source)).toBeUndefined();
|
||||
});
|
||||
|
||||
it('finds assignments to exports', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var Component = R.createClass({});',
|
||||
'exports.foo = 42;',
|
||||
'exports.Component = Component;'
|
||||
].join('\n');
|
||||
|
||||
expect(parse(source)).toBeDefined();
|
||||
});
|
||||
|
||||
it('errors if multiple components are exported', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'exports.ComponentA = ComponentA;',
|
||||
'exports.ComponentB = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
expect(function() {
|
||||
parse(source)
|
||||
}).toThrow();
|
||||
});
|
||||
|
||||
it('accepts multiple definitions if only one is exported', function() {
|
||||
var source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'exports.ComponentB = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
expect(parse(source)).toBeDefined();
|
||||
|
||||
source = [
|
||||
'var R = require("React");',
|
||||
'var ComponentA = R.createClass({});',
|
||||
'var ComponentB = R.createClass({});',
|
||||
'module.exports = ComponentB;'
|
||||
].join('\n');
|
||||
|
||||
expect(parse(source)).toBeDefined();
|
||||
});
|
||||
});
|
47
website/react-docgen/lib/strategies/findAllReactCreateClassCalls.js
vendored
Normal file
47
website/react-docgen/lib/strategies/findAllReactCreateClassCalls.js
vendored
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var isReactCreateClassCall = require('../utils/isReactCreateClassCall');
|
||||
var resolveToValue = require('../utils/resolveToValue');
|
||||
|
||||
/**
|
||||
* Given an AST, this function tries to find all object expressions that are
|
||||
* passed to `React.createClass` calls, by resolving all references properly.
|
||||
*/
|
||||
function findAllReactCreateClassCalls(
|
||||
ast: ASTNode,
|
||||
recast: Object
|
||||
): Array<NodePath> {
|
||||
var types = recast.types.namedTypes;
|
||||
var definitions = [];
|
||||
|
||||
recast.visit(ast, {
|
||||
visitCallExpression: function(path) {
|
||||
if (!isReactCreateClassCall(path)) {
|
||||
return false;
|
||||
}
|
||||
// We found React.createClass. Lets get cracking!
|
||||
var resolvedPath = resolveToValue(path.get('arguments', 0));
|
||||
if (types.ObjectExpression.check(resolvedPath.node)) {
|
||||
definitions.push(resolvedPath);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return definitions;
|
||||
}
|
||||
|
||||
module.exports = findAllReactCreateClassCalls;
|
78
website/react-docgen/lib/strategies/findExportedReactCreateClassCall.js
vendored
Normal file
78
website/react-docgen/lib/strategies/findExportedReactCreateClassCall.js
vendored
Normal file
@ -0,0 +1,78 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var isExportsOrModuleAssignment =
|
||||
require('../utils/isExportsOrModuleAssignment');
|
||||
var isReactCreateClassCall = require('../utils/isReactCreateClassCall');
|
||||
var resolveToValue = require('../utils/resolveToValue');
|
||||
|
||||
var ERROR_MULTIPLE_DEFINITIONS =
|
||||
'Multiple exported component definitions found.';
|
||||
|
||||
function ignore() {
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Given an AST, this function tries to find the object expression that is
|
||||
* passed to `React.createClass`, by resolving all references properly.
|
||||
*/
|
||||
function findExportedReactCreateClass(
|
||||
ast: ASTNode,
|
||||
recast: Object
|
||||
): ?NodePath {
|
||||
var types = recast.types.namedTypes;
|
||||
var definition;
|
||||
|
||||
recast.visit(ast, {
|
||||
visitFunctionDeclaration: ignore,
|
||||
visitFunctionExpression: ignore,
|
||||
visitIfStatement: ignore,
|
||||
visitWithStatement: ignore,
|
||||
visitSwitchStatement: ignore,
|
||||
visitCatchCause: ignore,
|
||||
visitWhileStatement: ignore,
|
||||
visitDoWhileStatement: ignore,
|
||||
visitForStatement: ignore,
|
||||
visitForInStatement: ignore,
|
||||
visitAssignmentExpression: function(path) {
|
||||
// Ignore anything that is not `exports.X = ...;` or
|
||||
// `module.exports = ...;`
|
||||
if (!isExportsOrModuleAssignment(path)) {
|
||||
return false;
|
||||
}
|
||||
// Resolve the value of the right hand side. It should resolve to a call
|
||||
// expression, something like React.createClass
|
||||
path = resolveToValue(path.get('right'));
|
||||
if (!isReactCreateClassCall(path)) {
|
||||
return false;
|
||||
}
|
||||
if (definition) {
|
||||
// If a file exports multiple components, ... complain!
|
||||
throw new Error(ERROR_MULTIPLE_DEFINITIONS);
|
||||
}
|
||||
// We found React.createClass. Lets get cracking!
|
||||
var resolvedPath = resolveToValue(path.get('arguments', 0));
|
||||
if (types.ObjectExpression.check(resolvedPath.node)) {
|
||||
definition = resolvedPath;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
});
|
||||
|
||||
return definition;
|
||||
}
|
||||
|
||||
module.exports = findExportedReactCreateClass;
|
36
website/react-docgen/lib/utils/__tests__/isExportsOrModuleAssignment-test.js
vendored
Normal file
36
website/react-docgen/lib/utils/__tests__/isExportsOrModuleAssignment-test.js
vendored
Normal file
@ -0,0 +1,36 @@
|
||||
"use strict";
|
||||
|
||||
jest.autoMockOff();
|
||||
|
||||
describe('isExportsOrModuleAssignment', function() {
|
||||
var recast;
|
||||
var isExportsOrModuleAssignment;
|
||||
|
||||
function parse(src) {
|
||||
return new recast.types.NodePath(
|
||||
recast.parse(src).program.body[0]
|
||||
);
|
||||
}
|
||||
|
||||
beforeEach(function() {
|
||||
isExportsOrModuleAssignment = require('../isExportsOrModuleAssignment');
|
||||
recast = require('recast');
|
||||
});
|
||||
|
||||
it('detects "module.exports = ...;"', function() {
|
||||
expect(isExportsOrModuleAssignment(parse('module.exports = foo;')))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it('detects "exports.foo = ..."', function() {
|
||||
expect(isExportsOrModuleAssignment(parse('exports.foo = foo;')))
|
||||
.toBe(true);
|
||||
});
|
||||
|
||||
it('does not accept "exports = foo;"', function() {
|
||||
// That doesn't actually export anything
|
||||
expect(isExportsOrModuleAssignment(parse('exports = foo;')))
|
||||
.toBe(false);
|
||||
});
|
||||
|
||||
});
|
37
website/react-docgen/lib/utils/isExportsOrModuleAssignment.js
vendored
Normal file
37
website/react-docgen/lib/utils/isExportsOrModuleAssignment.js
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var expressionTo = require('./expressionTo');
|
||||
var types = require('recast').types.namedTypes;
|
||||
|
||||
/**
|
||||
* Returns true if the expression is of form `exports.foo = ...;` or
|
||||
* `modules.exports = ...;`.
|
||||
*/
|
||||
function isExportsOrModuleAssignment(path: NodePath): boolean {
|
||||
if (types.ExpressionStatement.check(path.node)) {
|
||||
path = path.get('expression');
|
||||
}
|
||||
if (!types.AssignmentExpression.check(path.node) ||
|
||||
!types.MemberExpression.check(path.node.left)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var exprArr = expressionTo.Array(path.get('left'));
|
||||
return (exprArr[0] === 'module' && exprArr[1] === 'exports') ||
|
||||
exprArr[0] == 'exports';
|
||||
}
|
||||
|
||||
module.exports = isExportsOrModuleAssignment;
|
37
website/react-docgen/lib/utils/isReactCreateClassCall.js
vendored
Normal file
37
website/react-docgen/lib/utils/isReactCreateClassCall.js
vendored
Normal file
@ -0,0 +1,37 @@
|
||||
/*
|
||||
* Copyright (c) 2015, 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.
|
||||
*
|
||||
*/
|
||||
|
||||
/**
|
||||
* @flow
|
||||
*/
|
||||
"use strict";
|
||||
|
||||
var isReactModuleName = require('./isReactModuleName');
|
||||
var match = require('./match');
|
||||
var resolveToModule = require('./resolveToModule');
|
||||
var types = require('recast').types.namedTypes;
|
||||
|
||||
/**
|
||||
* Returns true if the expression is a function call of the form
|
||||
* `React.createClass(...)`.
|
||||
*/
|
||||
function isReactCreateClassCall(path: NodePath): boolean {
|
||||
if (types.ExpressionStatement.check(path.node)) {
|
||||
path = path.get('expression');
|
||||
}
|
||||
|
||||
if (!match(path.node, {callee: {property: {name: 'createClass'}}})) {
|
||||
return false;
|
||||
}
|
||||
var module = resolveToModule(path.get('callee', 'object'));
|
||||
return module && isReactModuleName(module);
|
||||
}
|
||||
|
||||
module.exports = isReactCreateClassCall;
|
@ -25,7 +25,7 @@
|
||||
"recast": "^0.9.17"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jest-cli": "^0.2.2",
|
||||
"jest-cli": "^0.3.0",
|
||||
"react-tools": "^0.12.2"
|
||||
},
|
||||
"jest": {
|
||||
|
@ -14,7 +14,8 @@ function splitHeader(content) {
|
||||
}
|
||||
}
|
||||
return {
|
||||
header: lines.slice(1, i + 1).join('\n'),
|
||||
header: i < lines.length - 1 ?
|
||||
lines.slice(1, i + 1).join('\n') : null,
|
||||
content: lines.slice(i + 1).join('\n')
|
||||
};
|
||||
}
|
||||
@ -47,6 +48,9 @@ function execute() {
|
||||
|
||||
// Extract markdown metadata header
|
||||
var both = splitHeader(content);
|
||||
if (!both.header) {
|
||||
return;
|
||||
}
|
||||
var lines = both.header.split('\n');
|
||||
for (var i = 0; i < lines.length - 1; ++i) {
|
||||
var keyvalue = lines[i].split(':');
|
||||
|
@ -1,4 +1,10 @@
|
||||
var docs = require('../react-docgen');
|
||||
var findExportedReactCreateClassCall = require(
|
||||
'../react-docgen/dist/strategies/findExportedReactCreateClassCall'
|
||||
);
|
||||
var findAllReactCreateClassCalls = require(
|
||||
'../react-docgen/dist/strategies/findAllReactCreateClassCalls'
|
||||
);
|
||||
var fs = require('fs');
|
||||
var path = require('path');
|
||||
var slugify = require('../core/slugify');
|
||||
@ -12,7 +18,14 @@ function getNameFromPath(filepath) {
|
||||
}
|
||||
|
||||
function docsToMarkdown(filepath, i) {
|
||||
var json = docs.parseSource(fs.readFileSync(filepath));
|
||||
var json = docs.parseSource(
|
||||
fs.readFileSync(filepath),
|
||||
function(node, recast) {
|
||||
return findExportedReactCreateClassCall(node, recast) ||
|
||||
findAllReactCreateClassCalls(node, recast)[0];
|
||||
}
|
||||
)
|
||||
|
||||
var componentName = getNameFromPath(filepath);
|
||||
|
||||
var res = [
|
||||
@ -45,7 +58,7 @@ var components = [
|
||||
'../Libraries/Components/TextInput/TextInput.ios.js',
|
||||
'../Libraries/Components/Touchable/TouchableHighlight.js',
|
||||
'../Libraries/Components/Touchable/TouchableWithoutFeedback.js',
|
||||
// '../Libraries/Components/View/View.js',
|
||||
'../Libraries/Components/View/View.js',
|
||||
];
|
||||
|
||||
module.exports = function() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user