diff --git a/website/react-docgen/README.md b/website/react-docgen/README.md index a59645b41..db9835fe9 100644 --- a/website/react-docgen/README.md +++ b/website/react-docgen/README.md @@ -4,7 +4,7 @@ It uses [recast][] to parse the source into an AST and provides methods to process this AST to extract the desired information. The output / return value is a JSON blob / JavaScript object. -It provides a default implementation for React components defined via `React.createClass`. These component definitions must follow certain guidelines in order to be analyzable (see below for more info) +It provides a default implementation for React components defined via `React.createClass`. These component definitions must follow certain guidelines in order to be analyzable (see below for more info). ## Install @@ -38,6 +38,9 @@ If a directory is passed, it is recursively traversed. By default, `react-docgen` will look for the exported component created through `React.createClass` in each file. Have a look below for how to customize this behavior. +Have a look at `example/` for an example of how to use the result to generate +a markdown version of the documentation. + ## API The tool can be used programmatically to extract component information and customize the extraction process: @@ -209,5 +212,11 @@ The structure of the JSON blob / JavaScript object is as follows: ["composes": ] } ``` +(`[...]` means the property may not exist if such information was not found in the component definition) + +- ``: For each prop that was found, there will be an entry in `props` under the same name. +- ``: The name of the type, which is usually corresponds to the function name in `React.PropTypes`. However, for types define with `oneOf`, we use `"enum"` and for `oneOfType` we use `"union"`. If a custom function is provided or the type cannot be resolved to anything of `React.PropTypes`, we use `"custom"`. +- ``: Some types accept parameters which define the type in more detail (such as `arrayOf`, `instanceOf`, `oneOf`, etc). Those are stored in ``. The data type of `` depends on the type definition. + [recast]: https://github.com/benjamn/recast diff --git a/website/react-docgen/example/buildDocs.sh b/website/react-docgen/example/buildDocs.sh new file mode 100755 index 000000000..6230fe3fb --- /dev/null +++ b/website/react-docgen/example/buildDocs.sh @@ -0,0 +1,42 @@ +#!/usr/bin/env node + +/** + * This example script expects a JSON blob generated by react-docgen as input, + * e.g. react-docgen components/* | buildDocs.sh + */ + +var fs = require('fs'); +var generateMarkdown = require('./generateMarkdown'); +var path = require('path'); + +var json = ''; +process.stdin.setEncoding('utf8'); +process.stdin.on('readable', function() { + var chunk = process.stdin.read(); + if (chunk !== null) { + json += chunk; + } +}); + +process.stdin.on('end', function() { + buildDocs(JSON.parse(json)); +}); + +function buildDocs(api) { + // api is an object keyed by filepath. We use the file name as component name. + for (var filepath in api) { + var name = getComponentName(filepath); + var markdown = generateMarkdown(name, api[filepath]); + fs.writeFileSync(name + '.md', markdown); + process.stdout.write(filepath + ' -> ' + name + '.md\n'); + } +} + +function getComponentName(filepath) { + var name = path.basename(filepath); + var ext; + while ((ext = path.extname(name))) { + name = name.substring(0, name.length - ext.length); + } + return name; +} diff --git a/website/react-docgen/example/components/Component.js b/website/react-docgen/example/components/Component.js new file mode 100644 index 000000000..e62f85af6 --- /dev/null +++ b/website/react-docgen/example/components/Component.js @@ -0,0 +1,27 @@ +var React = require('react'); +var Foo = require('Foo'); + +/** + * General component description. + */ +var Component = React.createClass({ + propTypes: { + ...Foo.propTypes, + /** + * Prop description + */ + bar: React.PropTypes.number + }, + + getDefaultProps: function() { + return { + bar: 21 + }; + }, + + render: function() { + // ... + } +}); + +module.exports = Component; diff --git a/website/react-docgen/example/components/NoComponent.js b/website/react-docgen/example/components/NoComponent.js new file mode 100644 index 000000000..96cf951e3 --- /dev/null +++ b/website/react-docgen/example/components/NoComponent.js @@ -0,0 +1,4 @@ +/** + * An example for a module that is not a component. + */ +module.exports = "abc"; diff --git a/website/react-docgen/example/generateMarkdown.js b/website/react-docgen/example/generateMarkdown.js new file mode 100644 index 000000000..b4018c052 --- /dev/null +++ b/website/react-docgen/example/generateMarkdown.js @@ -0,0 +1,80 @@ +/** + * 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"; + +function stringOfLength(string, length) { + var newString = ''; + for (var i = 0; i < length; i++) { + newString += string; + } + return newString; +} + +function generateTitle(name) { + var title = '`' + name + '` (component)'; + return title + '\n' + stringOfLength('=', title.length) + '\n'; +} + +function generateDesciption(description) { + return description + '\n'; +} + +function generatePropType(type) { + var values; + if (Array.isArray(type.value)) { + values = '(' + + type.value.map(function(typeValue) { + return typeValue.name || typeValue.value; + }).join('|') + + ')'; + } else { + values = type.value; + } + + return 'type: `' + type.name + (values ? values: '') + '`\n'; +} + +function generatePropDefaultValue(value) { + return 'defaultValue: `' + value.value + '`\n'; +} + +function generateProp(propName, prop) { + return ( + '### `' + propName + '`' + (prop.required ? ' (required)' : '') + '\n' + + '\n' + + (prop.description ? prop.description + '\n\n' : '') + + (prop.type ? generatePropType(prop.type) : '') + + (prop.defaultValue ? generatePropDefaultValue(prop.defaultValue) : '') + + '\n' + ); +} + +function generateProps(props) { + var title = 'Props'; + + return ( + title + '\n' + + stringOfLength('-', title.length) + '\n' + + '\n' + + Object.keys(props).sort().map(function(propName) { + return generateProp(propName, props[propName]); + }).join('\n') + ); +} + +function generateMarkdown(name, reactAPI) { + var markdownString = + generateTitle(name) + '\n' + + generateDesciption(reactAPI.description) + '\n' + + generateProps(reactAPI.props); + + return markdownString; +} + +module.exports = generateMarkdown; diff --git a/website/react-docgen/lib/ReactDocumentationParser.js b/website/react-docgen/lib/ReactDocumentationParser.js deleted file mode 100644 index 49914d60f..000000000 --- a/website/react-docgen/lib/ReactDocumentationParser.js +++ /dev/null @@ -1,124 +0,0 @@ -/* - * 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"; - -type Handler = (documentation: Documentation, path: NodePath) => void; - -var Documentation = require('./Documentation'); - -var findExportedReactCreateClass = - require('./strategies/findExportedReactCreateClassCall'); -var getPropertyName = require('./utils/getPropertyName'); -var recast = require('recast'); -var resolveToValue = require('./utils/resolveToValue'); -var n = recast.types.namedTypes; - -class ReactDocumentationParser { - _componentHandlers: Array; - _apiHandlers: Object; - - constructor() { - this._componentHandlers = []; - this._apiHandlers = Object.create(null); - } - - /** - * 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._apiHandlers[property]) { - this._apiHandlers[property] = []; - } - 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, - componentDefinitionStrategy?: - (program: ASTNode, recast: Object) => (Array|NodePath) - ): (Array|Object) { - if (!componentDefinitionStrategy) { - componentDefinitionStrategy = findExportedReactCreateClass; - } - var ast = recast.parse(source); - // Find the component definitions first. The return value should be - // an ObjectExpression. - var componentDefinition = componentDefinitionStrategy(ast.program, recast); - var isArray = Array.isArray(componentDefinition); - if (!componentDefinition || (isArray && componentDefinition.length === 0)) { - throw new Error(ReactDocumentationParser.ERROR_MISSING_DEFINITION); - } - - return isArray ? - this._executeHandlers(componentDefinition).map( - documentation => documentation.toObject() - ) : - this._executeHandlers([componentDefinition])[0].toObject(); - } - - _executeHandlers(componentDefinitions: Array): Array { - 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; - }); - } - -} - -ReactDocumentationParser.ERROR_MISSING_DEFINITION = - 'No suitable component definition found.'; - -module.exports = ReactDocumentationParser; diff --git a/website/react-docgen/lib/__tests__/ReactDocumentationParser-test.js b/website/react-docgen/lib/__tests__/ReactDocumentationParser-test.js deleted file mode 100644 index f0a865d1c..000000000 --- a/website/react-docgen/lib/__tests__/ReactDocumentationParser-test.js +++ /dev/null @@ -1,61 +0,0 @@ -/* - * 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 ReactDocumentationParser; - var parser; - var recast; - - beforeEach(function() { - recast = require('recast'); - ReactDocumentationParser = require('../ReactDocumentationParser'); - parser = new ReactDocumentationParser(); - }); - - 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(); - }); - - }); - -}); diff --git a/website/react-docgen/lib/handlers/__tests__/defaultValueHandler-test.js b/website/react-docgen/lib/handlers/__tests__/defaultValueHandler-test.js deleted file mode 100644 index 7902d3ee7..000000000 --- a/website/react-docgen/lib/handlers/__tests__/defaultValueHandler-test.js +++ /dev/null @@ -1,81 +0,0 @@ -/* - * 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(); - -var module_template = [ - 'var React = require("React");', - 'var PropTypes = React.PropTypes;', - 'var Component = React.createClass(%s);', - 'module.exports = Component;' -].join('\n'); - -function getSource(definition) { - return module_template.replace('%s', definition); -} - -describe('React documentation parser', function() { - var parser; - - beforeEach(function() { - parser = new (require('../../ReactDocumentationParser')); - parser.addHandler(require('../defaultValueHandler'), 'getDefaultProps'); - }); - - it ('should find prop default values that are literals', function() { - var source = getSource([ - '{', - ' getDefaultProps: function() {', - ' return {', - ' foo: "bar",', - ' bar: 42,', - ' baz: ["foo", "bar"],', - ' abc: {xyz: abc.def, 123: 42}', - ' };', - ' }', - '}' - ].join('\n')); - - var expectedResult = { - description: '', - props: { - foo: { - defaultValue: { - value: '"bar"', - computed: false - } - }, - bar: { - defaultValue: { - value: '42', - computed: false - } - }, - baz: { - defaultValue: { - value: '["foo", "bar"]', - computed: false - } - }, - abc: { - defaultValue: { - value: '{xyz: abc.def, 123: 42}', - computed: false - } - } - } - }; - - var result = parser.parseSource(source); - expect(result).toEqual(expectedResult); - }); -}); diff --git a/website/react-docgen/lib/handlers/__tests__/propDocblockHandler-test.js b/website/react-docgen/lib/handlers/__tests__/propDocblockHandler-test.js index 285e12a18..0fe18d228 100644 --- a/website/react-docgen/lib/handlers/__tests__/propDocblockHandler-test.js +++ b/website/react-docgen/lib/handlers/__tests__/propDocblockHandler-test.js @@ -25,12 +25,17 @@ describe('propDocblockHandler', function() { }); function parse(definition) { - return utils.parse('(' + definition + ')').get('body', 0, 'expression'); + var programPath = utils.parse(definition); + return programPath.get( + 'body', + programPath.node.body.length - 1, + 'expression' + ); } it('finds docblocks for prop types', function() { var definition = parse([ - '{', + '({', ' propTypes: {', ' /**', ' * Foo comment', @@ -42,7 +47,7 @@ describe('propDocblockHandler', function() { ' */', ' bar: Prop.bool,', ' }', - '}' + '})' ].join('\n')); propDocblockHandler(documentation, definition); @@ -58,7 +63,7 @@ describe('propDocblockHandler', function() { it('can handle multline comments', function() { var definition = parse([ - '{', + '({', ' propTypes: {', ' /**', ' * Foo comment with', @@ -68,7 +73,7 @@ describe('propDocblockHandler', function() { ' */', ' foo: Prop.bool', ' }', - '}' + '})' ].join('\n')); propDocblockHandler(documentation, definition); @@ -82,7 +87,7 @@ describe('propDocblockHandler', function() { it('ignores non-docblock comments', function() { var definition = parse([ - '{', + '({', ' propTypes: {', ' /**', ' * Foo comment', @@ -96,7 +101,7 @@ describe('propDocblockHandler', function() { ' /* This is not a doc comment */', ' bar: Prop.bool,', ' }', - '}' + '})' ].join('\n')); propDocblockHandler(documentation, definition); @@ -112,7 +117,7 @@ describe('propDocblockHandler', function() { it('only considers the comment with the property below it', function() { var definition = parse([ - '{', + '({', ' propTypes: {', ' /**', ' * Foo comment', @@ -120,7 +125,7 @@ describe('propDocblockHandler', function() { ' foo: Prop.bool,', ' bar: Prop.bool,', ' }', - '}' + '})' ].join('\n')); propDocblockHandler(documentation, definition); @@ -136,7 +141,7 @@ describe('propDocblockHandler', function() { it('understands and ignores the spread operator', function() { var definition = parse([ - '{', + '({', ' propTypes: {', ' ...Foo.propTypes,', ' /**', @@ -144,7 +149,28 @@ describe('propDocblockHandler', function() { ' */', ' foo: Prop.bool,', ' }', - '}' + '})' + ].join('\n')); + + propDocblockHandler(documentation, definition); + expect(documentation.descriptors).toEqual({ + foo: { + description: 'Foo comment' + } + }); + }); + + it('resolves variables', function() { + var definition = parse([ + 'var Props = {', + ' /**', + ' * Foo comment', + ' */', + ' foo: Prop.bool,', + '};', + '({', + ' propTypes: Props', + '})' ].join('\n')); propDocblockHandler(documentation, definition); diff --git a/website/react-docgen/lib/handlers/__tests__/propTypeHandler-test.js b/website/react-docgen/lib/handlers/__tests__/propTypeHandler-test.js index d8e41adff..79b06bc96 100644 --- a/website/react-docgen/lib/handlers/__tests__/propTypeHandler-test.js +++ b/website/react-docgen/lib/handlers/__tests__/propTypeHandler-test.js @@ -171,4 +171,21 @@ describe('propTypeHandler', function() { }, }); }); + + it('resolves variables', function() { + var definition = parse([ + 'var props = {bar: PropTypes.bool};', + '({', + ' propTypes: props', + '})', + ].join('\n')); + + propTypeHandler(documentation, definition); + expect(documentation.descriptors).toEqual({ + bar: { + type: {}, + required: false + }, + }); + }); }); diff --git a/website/react-docgen/lib/handlers/defaultValueHandler.js b/website/react-docgen/lib/handlers/defaultValueHandler.js deleted file mode 100644 index dd51d58d7..000000000 --- a/website/react-docgen/lib/handlers/defaultValueHandler.js +++ /dev/null @@ -1,77 +0,0 @@ -/* - * 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 Documentation = require('../Documentation'); - -var expressionTo = require('../utils/expressionTo'); -var getPropertyName = require('../utils/getPropertyName'); -var recast = require('recast'); -var resolveToValue = require('../utils/resolveToValue'); -var types = recast.types.namedTypes; -var visit = recast.types.visit; - -function getDefaultValue(path) { - var node = path.node; - var defaultValue; - if (types.Literal.check(node)) { - defaultValue = node.raw; - } else { - path = resolveToValue(path); - node = path.node; - defaultValue = recast.print(path).code; - } - if (typeof defaultValue !== 'undefined') { - return { - value: defaultValue, - computed: types.CallExpression.check(node) || - types.MemberExpression.check(node) || - types.Identifier.check(node) - }; - } -} - -function defaultValueHandler(documentation: Documentation, path: NodePath) { - if (!types.FunctionExpression.check(path.node)) { - return; - } - - // Find the value that is returned from the function and process it if it is - // an object literal. - var objectExpressionPath; - visit(path.get('body'), { - visitFunction: () => false, - visitReturnStatement: function(path) { - var resolvedPath = resolveToValue(path.get('argument')); - if (types.ObjectExpression.check(resolvedPath.node)) { - objectExpressionPath = resolvedPath; - } - return false; - } - }); - - if (objectExpressionPath) { - objectExpressionPath.get('properties').each(function(propertyPath) { - var propDescriptor = documentation.getPropDescriptor( - getPropertyName(propertyPath) - ); - var defaultValue = getDefaultValue(propertyPath.get('value')); - if (defaultValue) { - propDescriptor.defaultValue = defaultValue; - } - }); - } -} - -module.exports = defaultValueHandler; diff --git a/website/react-docgen/lib/handlers/propDocBlockHandler.js b/website/react-docgen/lib/handlers/propDocBlockHandler.js index eda9c8beb..940c66fa4 100644 --- a/website/react-docgen/lib/handlers/propDocBlockHandler.js +++ b/website/react-docgen/lib/handlers/propDocBlockHandler.js @@ -15,13 +15,14 @@ var Documentation = require('../Documentation'); -var types = require('recast').types.namedTypes; var getDocblock = require('../utils/docblock').getDocblock; var getPropertyName = require('../utils/getPropertyName'); var getPropertyValuePath = require('../utils/getPropertyValuePath'); +var types = require('recast').types.namedTypes; +var resolveToValue = require('../utils/resolveToValue'); function propDocBlockHandler(documentation: Documentation, path: NodePath) { - var propTypesPath = getPropertyValuePath(path, 'propTypes'); + var propTypesPath = resolveToValue(getPropertyValuePath(path, 'propTypes')); if (!propTypesPath || !types.ObjectExpression.check(propTypesPath.node)) { return; } diff --git a/website/react-docgen/lib/handlers/propTypeHandler.js b/website/react-docgen/lib/handlers/propTypeHandler.js index 37c00c937..ec1abe86a 100644 --- a/website/react-docgen/lib/handlers/propTypeHandler.js +++ b/website/react-docgen/lib/handlers/propTypeHandler.js @@ -100,7 +100,7 @@ function amendPropTypes(documentation, path) { } function propTypeHandler(documentation: Documentation, path: NodePath) { - var propTypesPath = getPropertyValuePath(resolveToValue(path), 'propTypes'); + var propTypesPath = resolveToValue(getPropertyValuePath(path, 'propTypes')); if (!propTypesPath || !types.ObjectExpression.check(propTypesPath.node)) { return; } diff --git a/website/react-docgen/lib/strategies/__tests__/findAllReactCreateClassCalls-test.js b/website/react-docgen/lib/strategies/__tests__/findAllReactCreateClassCalls-test.js deleted file mode 100644 index a78e6a77d..000000000 --- a/website/react-docgen/lib/strategies/__tests__/findAllReactCreateClassCalls-test.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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); - }); -}); diff --git a/website/react-docgen/lib/strategies/__tests__/findExportedReactCreateClassCall-test.js b/website/react-docgen/lib/strategies/__tests__/findExportedReactCreateClassCall-test.js deleted file mode 100644 index b0e4cba92..000000000 --- a/website/react-docgen/lib/strategies/__tests__/findExportedReactCreateClassCall-test.js +++ /dev/null @@ -1,106 +0,0 @@ -/* - * 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(); - }); -}); diff --git a/website/react-docgen/lib/strategies/findAllReactCreateClassCalls.js b/website/react-docgen/lib/strategies/findAllReactCreateClassCalls.js deleted file mode 100644 index 7971a1d26..000000000 --- a/website/react-docgen/lib/strategies/findAllReactCreateClassCalls.js +++ /dev/null @@ -1,47 +0,0 @@ -/* - * 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 { - 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; diff --git a/website/react-docgen/lib/strategies/findExportedReactCreateClassCall.js b/website/react-docgen/lib/strategies/findExportedReactCreateClassCall.js deleted file mode 100644 index ccb8a3907..000000000 --- a/website/react-docgen/lib/strategies/findExportedReactCreateClassCall.js +++ /dev/null @@ -1,78 +0,0 @@ -/* - * 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; diff --git a/website/react-docgen/package.json b/website/react-docgen/package.json index 45a16b5e1..b84e7cfb6 100644 --- a/website/react-docgen/package.json +++ b/website/react-docgen/package.json @@ -1,7 +1,12 @@ { "name": "react-docgen", "version": "1.0.0", - "description": "Extract information from React components for documentation generation", + "description": "A CLI and toolkit to extract information from React components for documentation generation.", + "repository": { + "type": "git", + "url": "https://github.com/reactjs/react-docgen.git" + }, + "bugs": "https://github.com/reactjs/react-docgen/issues", "bin": { "react-docgen": "bin/react-docgen.js" }, @@ -14,7 +19,7 @@ }, "keywords": [ "react", - "documentation" + "documentation-generation" ], "author": "Felix Kling", "license": "BSD-3-Clause",