Remove unused vendor files.

This commit is contained in:
John-David Dalton
2014-05-31 19:30:27 -05:00
parent 653aee8b07
commit 257ac4d37e
6 changed files with 0 additions and 1426 deletions

View File

@@ -1,38 +0,0 @@
<?php
// cleanup requested file path
$filePath = isset($_GET['f']) ? $_GET['f'] : 'lodash';
$filePath = preg_replace('#(\.*[\/])+#', '', $filePath);
$filePath .= preg_match('/\.[a-z]+$/', $filePath) ? '' : '.js';
// output filename
if (isset($_GET['o'])) {
$outputName = $_GET['o'];
} else if (isset($_SERVER['argv'][1])) {
$outputName = $_SERVER['argv'][1];
} else {
$outputName = basename($filePath);
}
/*--------------------------------------------------------------------------*/
require('../vendor/docdown/docdown.php');
// get package version
$version = json_decode(file_get_contents('../package.json'))->version;
// generate Markdown
$markdown = docdown(array(
'path' => '../' . $filePath,
'title' => '<a href="http://lodash.com/">Lo-Dash</a> <span>v' . $version . '</span>',
'toc' => 'categories',
'url' => 'https://github.com/lodash/lodash/blob/master/lodash.js'
));
// save to a `.md` file
file_put_contents($outputName . '.md', $markdown);
// print
header('Content-Type: text/plain;charset=utf-8');
echo $markdown . PHP_EOL;
?>

View File

@@ -1,20 +0,0 @@
Copyright 2011-2014 John-David Dalton <http://allyoucanleet.com/>
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

View File

@@ -1,38 +0,0 @@
<?php
/*!
* Docdown v1.0.0-pre
* Copyright 2011-2014 John-David Dalton <http://allyoucanleet.com/>
* Available under MIT license <http://mths.be/mit>
*/
require(dirname(__FILE__) . '/src/DocDown/MarkdownGenerator.php');
/**
* Generates Markdown from JSDoc entries in a given file.
*
* @param {Array} [$options=array()] The options array.
* @returns {string} The generated Markdown.
* @example
*
* // specify a file path
* $markdown = docdown(array(
* // path to js file
* 'path' => $filepath,
* // url used to reference line numbers in code
* 'url' => 'https://github.com/username/project/blob/master/my.js'
* ));
*
* // or pass raw js
* $markdown = docdown(array(
* // raw JavaScript source
* 'source' => $rawJS,
* // documentation title
* 'title' => 'My API Documentation',
* // url used to reference line numbers in code
* 'url' => 'https://github.com/username/project/blob/master/my.js'
* ));
*/
function docdown( $options = array() ) {
$gen = new MarkdownGenerator($options);
return $gen->generate();
}
?>

View File

@@ -1,226 +0,0 @@
<?php
/**
* A class to represent a JSDoc entry alias.
*/
class Alias {
/**
* The alias owner.
*
* @memberOf Alias
* @type Object
*/
public $owner;
/*--------------------------------------------------------------------------*/
/**
* The Alias constructor.
*
* @constructor
* @param {string} $name The alias name.
* @param {Object} $owner The alias owner.
*/
public function __construct( $name, $owner ) {
$this->owner = $owner;
$this->_name = $name;
$this->_call = $owner->getCall();
$this->_category = $owner->getCategory();
$this->_desc = $owner->getDesc();
$this->_example = $owner->getExample();
$this->_isCtor = $owner->isCtor();
$this->_isLicense = $owner->isLicense();
$this->_isPlugin = $owner->isPlugin();
$this->_isPrivate = $owner->isPrivate();
$this->_isStatic = $owner->isStatic();
$this->_lineNumber = $owner->getLineNumber();
$this->_members = $owner->getMembers();
$this->_params = $owner->getParams();
$this->_returns = $owner->getReturns();
$this->_type = $owner->getType();
}
/*--------------------------------------------------------------------------*/
/**
* Extracts the entry's `alias` objects.
*
* @memberOf Alias
* @param {number} $index The index of the array value to return.
* @returns {Array|string} The entry's `alias` objects.
*/
public function getAliases( $index = null ) {
$result = array();
return $index !== null
? @$result[$index]
: $result;
}
/**
* Extracts the function call from the owner entry.
*
* @memberOf Alias
* @returns {string} The function call.
*/
public function getCall() {
return $this->_call;
}
/**
* Extracts the owner entry's `category` data.
*
* @memberOf Alias
* @returns {string} The owner entry's `category` data.
*/
public function getCategory() {
return $this->_category;
}
/**
* Extracts the owner entry's description.
*
* @memberOf Alias
* @returns {string} The owner entry's description.
*/
public function getDesc() {
return $this->_desc;
}
/**
* Extracts the owner entry's `example` data.
*
* @memberOf Alias
* @returns {string} The owner entry's `example` data.
*/
public function getExample() {
return $this->_example;
}
/**
* Checks if the entry is an alias.
*
* @memberOf Alias
* @returns {boolean} Returns `true`.
*/
public function isAlias() {
return true;
}
/**
* Checks if the owner entry is a constructor.
*
* @memberOf Alias
* @returns {boolean} Returns `true` if a constructor, else `false`.
*/
public function isCtor() {
return $this->_isCtor;
}
/**
* Checks if the owner entry is a license.
*
* @memberOf Alias
* @returns {boolean} Returns `true` if a license, else `false`.
*/
public function isLicense() {
return $this->_isLicense;
}
/**
* Checks if the owner entry *is* assigned to a prototype.
*
* @memberOf Alias
* @returns {boolean} Returns `true` if assigned to a prototype, else `false`.
*/
public function isPlugin() {
return $this->_isPlugin;
}
/**
* Checks if the owner entry is private.
*
* @memberOf Alias
* @returns {boolean} Returns `true` if private, else `false`.
*/
public function isPrivate() {
return $this->_isPrivate;
}
/**
* Checks if the owner entry is *not* assigned to a prototype.
*
* @memberOf Alias
* @returns {boolean} Returns `true` if not assigned to a prototype, else `false`.
*/
public function isStatic() {
return $this->_isStatic;
}
/**
* Resolves the owner entry's line number.
*
* @memberOf Alias
* @returns {number} The owner entry's line number.
*/
public function getLineNumber() {
return $this->_lineNumber;
}
/**
* Extracts the owner entry's `member` data.
*
* @memberOf Alias
* @param {number} $index The index of the array value to return.
* @returns {Array|string} The owner entry's `member` data.
*/
public function getMembers( $index = null ) {
return $index !== null
? @$this->_members[$index]
: $this->_members;
}
/**
* Extracts the owner entry's `name` data.
*
* @memberOf Alias
* @returns {string} The owner entry's `name` data.
*/
public function getName() {
return $this->_name;
}
/**
* Extracts the owner entry's `param` data.
*
* @memberOf Alias
* @param {number} $index The index of the array value to return.
* @returns {Array} The owner entry's `param` data.
*/
public function getParams( $index = null ) {
return $index !== null
? @$this->_params[$index]
: $this->_params;
}
/**
* Extracts the owner entry's `returns` data.
*
* @memberOf Alias
* @returns {string} The owner entry's `returns` data.
*/
public function getReturns() {
return $this->_returns;
}
/**
* Extracts the owner entry's `type` data.
*
* @memberOf Alias
* @returns {string} The owner entry's `type` data.
*/
public function getType() {
return $this->_type;
}
}
?>

View File

@@ -1,456 +0,0 @@
<?php
require(dirname(__FILE__) . "/Alias.php");
/**
* A class to simplify parsing a single JSDoc entry.
*/
class Entry {
/**
* The documentation entry.
*
* @memberOf Entry
* @type string
*/
public $entry = '';
/**
* The language highlighter used for code examples.
*
* @memberOf Entry
* @type string
*/
public $lang = '';
/**
* The source code.
*
* @memberOf Entry
* @type string
*/
public $source = '';
/*--------------------------------------------------------------------------*/
/**
* The Entry constructor.
*
* @constructor
* @param {string} $entry The documentation entry to analyse.
* @param {string} $source The source code.
* @param {string} [$lang ='js'] The language highlighter used for code examples.
*/
public function __construct( $entry, $source, $lang = 'js' ) {
$this->entry = $entry;
$this->lang = $lang;
$this->source = str_replace(PHP_EOL, "\n", $source);
}
/*--------------------------------------------------------------------------*/
/**
* Extracts the documentation entries from source code.
*
* @static
* @memberOf Entry
* @param {string} $source The source code.
* @returns {Array} The array of entries.
*/
public static function getEntries( $source ) {
preg_match_all('#/\*\*(?![-!])[\s\S]*?\*/\s*.+#', $source, $result);
return array_pop($result);
}
/*--------------------------------------------------------------------------*/
/**
* Checks if the entry is a function reference.
*
* @private
* @memberOf Entry
* @returns {boolean} Returns `true` if the entry is a function reference, else `false`.
*/
private function isFunction() {
if (!isset($this->_isFunction)) {
$this->_isFunction = !!(
$this->isCtor() ||
count($this->getParams()) ||
count($this->getReturns()) ||
preg_match('/\*[\t ]*@function\b/', $this->entry) ||
preg_match('#\*/\s*function #', $this->entry)
);
}
return $this->_isFunction;
}
/*--------------------------------------------------------------------------*/
/**
* Extracts the entry's `alias` objects.
*
* @memberOf Entry
* @param {number} $index The index of the array value to return.
* @returns {Array|string} The entry's `alias` objects.
*/
public function getAliases( $index = null ) {
if (!isset($this->_aliases)) {
preg_match('#\*[\t ]*@alias\s+(.+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
$result = preg_split('/,\s*/', $result);
natsort($result);
foreach ($result as $resultIndex => $value) {
$result[$resultIndex] = new Alias($value, $this);
}
}
$this->_aliases = $result;
}
return $index !== null
? @$this->_aliases[$index]
: $this->_aliases;
}
/**
* Extracts the function call from the entry.
*
* @memberOf Entry
* @returns {string} The function call.
*/
public function getCall() {
if (isset($this->_call)) {
return $this->_call;
}
preg_match('#\*/\s*(?:function ([^(]*)|(.*?)(?=[:=,]|return\b))#', $this->entry, $result);
if ($result = array_pop($result)) {
$result = array_pop(explode('var ', trim(trim(array_pop(explode('.', $result))), "'")));
}
// resolve name
// avoid $this->getName() because it calls $this->getCall()
preg_match('#\*[\t ]*@name\s+(.+)#', $this->entry, $name);
if (count($name)) {
$name = trim($name[1]);
} else {
$name = $result;
}
// compile function call syntax
if ($this->isFunction()) {
// compose parts
$result = array($result);
$params = $this->getParams();
$paramNames = array();
foreach ($params as $param) {
// skip params that are properties of other params (e.g. `options.leading`)
preg_match('/\w+(?=\.[\w.]+)/', $param[1], $parentParam);
$parentParam = $parentParam[0];
if (!in_array($parentParam, $paramNames)) {
$result[] = $param[1];
}
$paramNames[] = preg_replace('/^\[|\]$/', '', $param[1]);
}
// format
$result = $name .'('. implode(array_slice($result, 1), ', ') .')';
}
$this->_call = $result ? $result : $name;
return $this->_call;
}
/**
* Extracts the entry's `category` data.
*
* @memberOf Entry
* @returns {string} The entry's `category` data.
*/
public function getCategory() {
if (isset($this->_category)) {
return $this->_category;
}
preg_match('#\*[\t ]*@category\s+(.+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
} else {
$result = $this->getType() == 'Function' ? 'Methods' : 'Properties';
}
$this->_category = $result;
return $result;
}
/**
* Extracts the entry's description.
*
* @memberOf Entry
* @returns {string} The entry's description.
*/
public function getDesc() {
if (isset($this->_desc)) {
return $this->_desc;
}
preg_match('#/\*\*(?:\s*\*)?([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
if (count($result)) {
$type = $this->getType();
$result = preg_replace('/:\n[\t ]*\*[\t ]*/', ":<br>\n", $result[1]);
$result = preg_replace('/(?:^|\n)[\t ]*\*\n[\t ]*\*[\t ]*/', "\n\n", $result);
$result = preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result);
$result = trim($result);
$result = ($type == 'Function' ? '' : '(' . str_replace('|', ', ', trim($type, '{}')) . '): ') . $result;
}
$this->_desc = $result;
return $result;
}
/**
* Extracts the entry's `example` data.
*
* @memberOf Entry
* @returns {string} The entry's `example` data.
*/
public function getExample() {
if (isset($this->_example)) {
return $this->_example;
}
preg_match('#\*[\t ]*@example\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', "\n", $result[1]));
$result = '```' . $this->lang . "\n" . $result . "\n```";
}
$this->_example = $result;
return $result;
}
/**
* Checks if the entry is an alias.
*
* @memberOf Entry
* @returns {boolean} Returns `false`.
*/
public function isAlias() {
return false;
}
/**
* Checks if the entry is a constructor.
*
* @memberOf Entry
* @returns {boolean} Returns `true` if a constructor, else `false`.
*/
public function isCtor() {
if (!isset($this->_isCtor)) {
$this->_isCtor = !!preg_match('/\*[\t ]*@constructor\b/', $this->entry);
}
return $this->_isCtor;
}
/**
* Checks if the entry is a license.
*
* @memberOf Entry
* @returns {boolean} Returns `true` if a license, else `false`.
*/
public function isLicense() {
if (!isset($this->_isLicense)) {
$this->_isLicense = !!preg_match('/\*[\t ]*@license\b/', $this->entry);
}
return $this->_isLicense;
}
/**
* Checks if the entry *is* assigned to a prototype.
*
* @memberOf Entry
* @returns {boolean} Returns `true` if assigned to a prototype, else `false`.
*/
public function isPlugin() {
if (!isset($this->_isPlugin)) {
$this->_isPlugin = !$this->isCtor() && !$this->isPrivate() && !$this->isStatic();
}
return $this->_isPlugin;
}
/**
* Checks if the entry is private.
*
* @memberOf Entry
* @returns {boolean} Returns `true` if private, else `false`.
*/
public function isPrivate() {
if (!isset($this->_isPrivate)) {
$this->_isPrivate = $this->isLicense() || !!preg_match('/\*[\t ]*@private\b/', $this->entry) || !preg_match('/\*[\t ]*@[a-z]+\b/', $this->entry);
}
return $this->_isPrivate;
}
/**
* Checks if the entry is *not* assigned to a prototype.
*
* @memberOf Entry
* @returns {boolean} Returns `true` if not assigned to a prototype, else `false`.
*/
public function isStatic() {
if (isset($this->_isStatic)) {
return $this->_isStatic;
}
$public = !$this->isPrivate();
$result = $public && !!preg_match('/\*[\t ]*@static\b/', $this->entry);
// set in cases where it isn't explicitly stated
if ($public && !$result) {
if ($parent = array_pop(preg_split('/[#.]/', $this->getMembers(0)))) {
foreach (Entry::getEntries($this->source) as $entry) {
$entry = new Entry($entry, $this->source);
if ($entry->getName() == $parent) {
$result = !$entry->isCtor();
break;
}
}
} else {
$result = true;
}
}
$this->_isStatic = $result;
return $result;
}
/**
* Resolves the entry's line number.
*
* @memberOf Entry
* @returns {number} The entry's line number.
*/
public function getLineNumber() {
if (!isset($this->_lineNumber)) {
preg_match_all('/\n/', substr($this->source, 0, strrpos($this->source, $this->entry) + strlen($this->entry)), $lines);
$this->_lineNumber = count(array_pop($lines)) + 1;
}
return $this->_lineNumber;
}
/**
* Extracts the entry's `member` data.
*
* @memberOf Entry
* @param {number} $index The index of the array value to return.
* @returns {Array|string} The entry's `member` data.
*/
public function getMembers( $index = null ) {
if (!isset($this->_members)) {
preg_match('#\*[\t ]*@member(?:Of)?\s+(.+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
$result = preg_split('/,\s*/', $result);
natsort($result);
}
$this->_members = $result;
}
return $index !== null
? @$this->_members[$index]
: $this->_members;
}
/**
* Extracts the entry's `name` data.
*
* @memberOf Entry
* @returns {string} The entry's `name` data.
*/
public function getName() {
if (isset($this->_name)) {
return $this->_name;
}
preg_match('#\*[\t ]*@name\s+(.+)#', $this->entry, $result);
if (count($result)) {
$result = trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]));
} else {
$result = array_shift(explode('(', $this->getCall()));
}
$this->_name = $result;
return $result;
}
/**
* Extracts the entry's `param` data.
*
* @memberOf Entry
* @param {number} $index The index of the array value to return.
* @returns {Array} The entry's `param` data.
*/
public function getParams( $index = null ) {
if (!isset($this->_params)) {
preg_match_all('#\*[\t ]*@param\s+\{\(?([^})]+)\)?\}\s+(\[.+\]|[$\w|]+(?:\[.+\])?)\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#i', $this->entry, $matchTuples);
$matchTuples = array_filter(array_slice($matchTuples, 1));
$result = array();
if (count($matchTuples)) {
foreach ($matchTuples as $tupleKey => $tuple) {
foreach ($tuple as $key => $value) {
if (!isset($result[$key])) {
$result[$key] = array();
}
$result[$key][] = $tupleKey
? trim(preg_replace('/(?:^|\n)[\t ]*\*[\t ]*/', ' ', $value))
: trim($value);
}
}
}
$this->_params = $result;
}
return $index !== null
? @$this->_params[$index]
: $this->_params;
}
/**
* Extracts the entry's `returns` data.
*
* @memberOf Entry
* @returns {string} The entry's `returns` data.
*/
public function getReturns() {
if (isset($this->_returns)) {
return $this->_returns;
}
preg_match('#\*[\t ]*@returns\s+\{([^}]+)\}\s+([\s\S]*?)(?=\*\s\@[a-z]|\*/)#', $this->entry, $result);
if (count($result)) {
$result = array_map('trim', array_slice($result, 1));
$result[0] = str_replace('|', ', ', $result[0]);
$result[1] = preg_replace('/(?:^|\n)[\t ]*\*[\t ]?/', ' ', $result[1]);
}
$this->_returns = $result;
return $result;
}
/**
* Extracts the entry's `type` data.
*
* @memberOf Entry
* @returns {string} The entry's `type` data.
*/
public function getType() {
if (isset($this->_type)) {
return $this->_type;
}
preg_match('#\*[\t ]*@type\s(?:\{\(?)?([^)}\n]+)#', $this->entry, $result);
if (count($result)) {
$result = trim($result[1]);
if (preg_match('/^(?:array|function|object|regexp)$/', $result)) {
$result = ucfirst($result);
}
} else {
$result = $this->isFunction() ? 'Function' : 'unknown';
}
$this->_type = $result;
return $result;
}
}
?>

View File

@@ -1,648 +0,0 @@
<?php
require(dirname(__FILE__) . "/Entry.php");
/**
* Generates Markdown from JSDoc entries.
*/
class MarkdownGenerator {
/**
* The HTML for the close tag.
*
* @static
* @memberOf MarkdownGenerator
* @type string
*/
public $closeTag = "\n<!-- /div -->\n";
/**
* An array of JSDoc entries.
*
* @memberOf MarkdownGenerator
* @type Array
*/
public $entries = array();
/**
* The HTML for the open tag.
*
* @memberOf MarkdownGenerator
* @type string
*/
public $openTag = "\n<!-- div -->\n";
/**
* An options array used to configure the generator.
*
* @memberOf MarkdownGenerator
* @type Array
*/
public $options = array();
/**
* The file's source code.
*
* @memberOf MarkdownGenerator
* @type string
*/
public $source = '';
/**
* The array of code snippets that are tokenized by `escape`.
*
* @private
* @memberOf MarkdownGenerator
* @type Array
*/
private $snippets = array();
/*--------------------------------------------------------------------------*/
/**
* The MarkdownGenerator constructor.
*
* @constructor
* @param {string} $source The source code to parse.
* @param {Array} $options The options array.
*/
public function __construct( $source, $options = array() ) {
// juggle arguments
if (is_array($source)) {
$options = $source;
} else {
$options['source'] = $source;
}
if (isset($options['source']) && realpath($options['source'])) {
$options['path'] = $options['source'];
}
if (isset($options['path'])) {
preg_match('/(?<=\.)[a-z]+$/', $options['path'], $ext);
$options['source'] = file_get_contents($options['path']);
$ext = array_pop($ext);
if (!isset($options['lang']) && $ext) {
$options['lang'] = $ext;
}
if (!isset($options['title'])) {
$options['title'] = ucfirst(basename($options['path'])) . ' API documentation';
}
}
if (!isset($options['lang'])) {
$options['lang'] = 'js';
}
if (!isset($options['toc'])) {
$options['toc'] = 'properties';
}
$this->options = $options;
$this->source = str_replace(PHP_EOL, "\n", $options['source']);
$this->entries = Entry::getEntries($this->source);
foreach ($this->entries as $index => $value) {
$this->entries[$index] = new Entry($value, $this->source, $options['lang']);
}
}
/*--------------------------------------------------------------------------*/
/**
* Performs common string formatting operations.
*
* @private
* @static
* @memberOf MarkdownGenerator
* @param {string} $string The string to format.
* @returns {string} The formatted string.
*/
private static function format( $string ) {
$counter = 0;
// tokenize inline code snippets
preg_match_all('/`[^`]+`/', $string, $tokenized);
$tokenized = $tokenized[0];
foreach ($tokenized as $snippet) {
$string = str_replace($snippet, '__token' . ($counter++) .'__', $string);
}
// italicize parentheses
$string = preg_replace('/(^|\s)(\([^)]+\))/', '$1*$2*', $string);
// mark numbers as inline code
$string = preg_replace('/[\t ](-?\d+(?:.\d+)?)(?!\.[^\n])/', ' `$1`', $string);
// detokenize inline code snippets
$counter = 0;
foreach ($tokenized as $snippet) {
$string = str_replace('__token' . ($counter++) . '__', $snippet, $string);
}
return trim($string);
}
/**
* Modify a string by replacing named tokens with matching assoc. array values.
*
* @private
* @static
* @memberOf MarkdownGenerator
* @param {string} $string The string to modify.
* @param {Array|Object} $object The template object.
* @returns {string} The modified string.
*/
private static function interpolate( $string, $object ) {
preg_match_all('/#\{([^}]+)\}/', $string, $tokens);
$tokens = array_unique(array_pop($tokens));
foreach ($tokens as $token) {
$pattern = '/#\{' . preg_replace('/([.*+?^${}()|[\]\\\])/', '\\\$1', $token) . '\}/';
$replacement = '';
if (is_object($object)) {
preg_match('/\(([^)]+?)\)$/', $token, $args);
$args = preg_split('/,\s*/', array_pop($args));
$method = 'get' . ucfirst(preg_replace('/\([^)]+?\)$/', '', $token));
if (method_exists($object, $method)) {
$replacement = (string) call_user_func_array(array($object, $method), $args);
} else if (isset($object->{$token})) {
$replacement = (string) $object->{$token};
}
} else if (isset($object[$token])) {
$replacement = (string) $object[$token];
}
$string = preg_replace($pattern, trim($replacement), $string);
}
return MarkdownGenerator::format($string);
}
/*--------------------------------------------------------------------------*/
/**
* Adds the given `$entries` to the `$result` array.
*
* @private
* @memberOf MarkdownGenerator
* @param {Array} $result The result array to modify.
* @param {Array} $entries The entries to add to the `$result`.
*/
private function addEntries( &$result, $entries ) {
foreach ($entries as $entry) {
// skip aliases
if ($entry->isAlias()) {
continue;
}
// name and description
array_push(
$result,
$this->openTag,
MarkdownGenerator::interpolate("### <a id=\"#{hash}\"></a>`#{member}#{separator}#{call}`\n<a href=\"##{hash}\">#</a> [&#x24C8;](#{href} \"View in source\") [&#x24C9;][1]\n\n#{desc}", array(
'call' => $entry->getCall(),
'desc' => $this->escape($entry->getDesc()),
'hash' => $entry->hash,
'href' => $entry->href,
'member' => $entry->member,
'separator' => $entry->separator
))
);
// @alias
if (count($aliases = $entry->getAliases())) {
array_push($result, '', '#### Aliases');
foreach ($aliases as $index => $alias) {
$aliases[$index] = MarkdownGenerator::interpolate('#{member}#{separator}#{name}', $alias);
}
$result[] = '*' . implode(', ', $aliases) . '*';
}
// @param
if (count($params = $entry->getParams())) {
array_push($result, '', '#### Arguments');
foreach ($params as $index => $param) {
$result[] = MarkdownGenerator::interpolate('#{num}. `#{name}` (#{type}): #{desc}', array(
'desc' => $this->escape($param[2]),
'name' => $param[1],
'num' => $index + 1,
'type' => $this->escape($param[0])
));
}
}
// @returns
if (count($returns = $entry->getReturns())) {
array_push(
$result, '',
'#### Returns',
MarkdownGenerator::interpolate('(#{type}): #{desc}', array(
'desc' => $this->escape($returns[1]),
'type' => $this->escape($returns[0])
))
);
}
// @example
if ($example = $entry->getExample()) {
array_push($result, '', '#### Example', $example);
}
array_push($result, "\n* * *", $this->closeTag);
}
}
/**
* Escapes special Markdown characters.
*
* @private
* @memberOf Entry
* @param {string} $string The string to escape.
* @returns {string} Returns the escaped string.
*/
private function escape( $string ) {
$string = preg_replace_callback('/`.*?\`/', array($this, 'swapSnippetsToTokens'), $string);
$string = preg_replace('/(?<!\\\)\*/', '&#42;', $string);
$string = preg_replace('/(?<!\\\)\[/', '&#91;', $string);
$string = preg_replace('/(?<!\\\)\]/', '&#93;', $string);
$string = preg_replace_callback('/@@token@@/', array($this, 'swapTokensToSnippets'), $string);
return $string;
}
/**
* Resolves the entry's hash used to navigate the documentation.
*
* @private
* @memberOf MarkdownGenerator
* @param {number|Object} $entry The entry object.
* @param {string} $member The name of the member.
* @returns {string} The url hash.
*/
private function getHash( $entry, $member = '' ) {
$entry = is_numeric($entry) ? $this->entries[$entry] : $entry;
$member = !$member ? $entry->getMembers(0) : $member;
$result = ($member ? $member . ($entry->isPlugin() ? 'prototype' : '') : '') . $entry->getCall();
$result = preg_replace('/\(\[|\[\]/', '', $result);
$result = preg_replace('/[\t =|\'"{}.()\]]/', '', $result);
$result = preg_replace('/[\[#,]+/', '-', $result);
return strtolower($result);
}
/**
* Resolves the entry's url for the specific line number.
*
* @private
* @memberOf MarkdownGenerator
* @param {number|Object} $entry The entry object.
* @returns {string} The url.
*/
private function getLineUrl( $entry ) {
$entry = is_numeric($entry) ? $this->entries($entry) : $entry;
return $this->options['url'] . '#L' . $entry->getLineNumber();
}
/**
* Extracts the character used to separate the entry's name from its member.
*
* @private
* @memberOf MarkdownGenerator
* @param {number|Object} $entry The entry object.
* @returns {string} The separator.
*/
private function getSeparator( $entry ) {
$entry = is_numeric($entry) ? $this->entries($entry) : $entry;
return $entry->isPlugin() ? '.prototype.' : '.';
}
/**
* Swaps code snippets with tokens as a `preg_replace_callback` callback
* used by `escape`.
*
* @private
* @memberOf Entry
* @param {Array} $matches The array of regexp matches.
* @returns {string} Returns the token.
*/
private function swapSnippetsToTokens( $matches ) {
$this->snippets[] = $matches[0];
return '@@token@@';
}
/**
* Swaps tokens with code snippets as a `preg_replace_callback` callback
* used by `escape`.
*
* @private
* @memberOf Entry
* @returns {string} Returns the code snippet.
*/
private function swapTokensToSnippets() {
return array_shift($this->snippets);
}
/*--------------------------------------------------------------------------*/
/**
* Generates Markdown from JSDoc entries.
*
* @memberOf MarkdownGenerator
* @returns {string} The rendered Markdown.
*/
public function generate() {
$api = array();
$byCategory = $this->options['toc'] == 'categories';
$categories = array();
$closeTag = $this->closeTag;
$compiling = false;
$openTag = $this->openTag;
$result = array('# ' . $this->options['title']);
$toc = 'toc';
// initialize $api array
foreach ($this->entries as $entry) {
// skip invalid or private entries
$name = $entry->getName();
if (!$name || $entry->isPrivate()) {
continue;
}
$members = $entry->getMembers();
$members = count($members) ? $members : array('');
foreach ($members as $member) {
// create api category arrays
if ($member && !isset($api[$member])) {
// create temporary entry to be replaced later
$api[$member] = new stdClass;
$api[$member]->static = array();
$api[$member]->plugin = array();
}
// append entry to api member
if (!$member || $entry->isCtor() || ($entry->getType() == 'Object' &&
!preg_match('/[=:]\s*(?:null|undefined)\s*[,;]?$/', $entry->entry))) {
// assign the real entry, replacing the temporary entry if it exist
$member = ($member ? $member . ($entry->isPlugin() ? '#' : '.') : '') . $name;
$entry->static = @$api[$member] ? $api[$member]->static : array();
$entry->plugin = @$api[$member] ? $api[$member]->plugin : array();
$api[$member] = $entry;
foreach ($entry->getAliases() as $alias) {
$api[$member]->static[] = $alias;
}
}
else if ($entry->isStatic()) {
$api[$member]->static[] = $entry;
foreach ($entry->getAliases() as $alias) {
$api[$member]->static[] = $alias;
}
}
else if (!$entry->isCtor()) {
$api[$member]->plugin[] = $entry;
foreach ($entry->getAliases() as $alias) {
$api[$member]->plugin[] = $alias;
}
}
}
}
// add properties to each entry
foreach ($api as $entry) {
$entry->hash = $this->getHash($entry);
$entry->href = $this->getLineUrl($entry);
$entry->separator = '';
$member = $entry->getMembers(0);
$member = ($member ? $member . $this->getSeparator($entry) : '') . $entry->getName();
$entry->member = preg_replace('/' . $entry->getName() . '$/', '', $member);
// add properties to static and plugin sub-entries
foreach (array('static', 'plugin') as $kind) {
foreach ($entry->{$kind} as $subentry) {
$subentry->hash = $this->getHash($subentry);
$subentry->href = $this->getLineUrl($subentry);
$subentry->member = $member;
$subentry->separator = $this->getSeparator($subentry);
}
}
}
/*------------------------------------------------------------------------*/
// custom sort for root level entries
// TODO: see how well it handles deeper namespace traversal
function sortCompare($a, $b) {
$score = array( 'a' => 0, 'b' => 0);
foreach (array( 'a' => $a, 'b' => $b) as $key => $value) {
// capitalized properties are last
if (preg_match('/[#.][A-Z]/', $value)) {
$score[$key] = 0;
}
// lowercase prototype properties are next to last
else if (preg_match('/#[a-z]/', $value)) {
$score[$key] = 1;
}
// lowercase static properties next to first
else if (preg_match('/\.[a-z]/', $value)) {
$score[$key] = 2;
}
// root properties are first
else if (preg_match('/^[^#.]+$/', $value)) {
$score[$key] = 3;
}
}
$score = $score['b'] - $score['a'];
return $score ? $score : strcasecmp($a, $b);
}
uksort($api, 'sortCompare');
// sort static and plugin sub-entries
foreach ($api as $entry) {
foreach (array('static', 'plugin') as $kind) {
$sortBy = array( 'a' => array(), 'b' => array(), 'c' => array() );
foreach ($entry->{$kind} as $subentry) {
$name = $subentry->getName();
// functions w/o ALL-CAPs names are last
$sortBy['a'][] = $subentry->getType() == 'Function' && !preg_match('/^[A-Z_]+$/', $name);
// ALL-CAPs properties first
$sortBy['b'][] = preg_match('/^[A-Z_]+$/', $name);
// lowercase alphanumeric sort
$sortBy['c'][] = strtolower($name);
}
array_multisort($sortBy['a'], SORT_ASC, $sortBy['b'], SORT_DESC, $sortBy['c'], SORT_ASC, $entry->{$kind});
}
}
/*------------------------------------------------------------------------*/
// add categories
foreach ($api as $entry) {
$categories[$entry->getCategory()][] = $entry;
foreach (array('static', 'plugin') as $kind) {
foreach ($entry->{$kind} as $subentry) {
$categories[$subentry->getCategory()][] = $subentry;
}
}
}
// sort categories
ksort($categories);
foreach(array('Methods', 'Properties') as $category) {
if (isset($categories[$category])) {
$entries = $categories[$category];
unset($categories[$category]);
$categories[$category] = $entries;
}
}
/*------------------------------------------------------------------------*/
// compile TOC
$result[] = $openTag;
// compile TOC by categories
if ($byCategory) {
foreach ($categories as $category => $entries) {
if ($compiling) {
$result[] = $closeTag;
} else {
$compiling = true;
}
// assign TOC hash
if (count($result) == 2) {
$toc = strtolower($category);
}
// add category
array_push(
$result,
$openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $category . '`'
);
// add entries
foreach ($entries as $entry) {
if ($entry->isAlias()) {
$result[] = MarkdownGenerator::interpolate('* <a href="##{hash}" class="alias">`#{member}#{separator}#{name}` -> `#{realName}`</a>', array(
'hash' => $entry->hash,
'member' => $entry->member,
'name' => $entry->getName(),
'realName' => $entry->owner->getName(),
'separator' => $entry->separator
));
}
else {
$result[] = MarkdownGenerator::interpolate('* <a href="##{hash}">`#{member}#{separator}#{name}`</a>', $entry);
}
}
}
}
// compile TOC by namespace
else {
foreach ($api as $entry) {
if ($compiling) {
$result[] = $closeTag;
} else {
$compiling = true;
}
$member = $entry->member . $entry->getName();
// assign TOC hash
if (count($result) == 2) {
$toc = $member;
}
// add root entry
array_push(
$result,
$openTag, '## ' . (count($result) == 2 ? '<a id="' . $toc . '"></a>' : '') . '`' . $member . '`',
MarkdownGenerator::interpolate('* [`' . $member . '`](##{hash})', $entry)
);
// add static and plugin sub-entries
foreach (array('static', 'plugin') as $kind) {
if ($kind == 'plugin' && count($entry->plugin)) {
array_push(
$result,
$closeTag,
$openTag,
'## `' . $member . ($entry->isCtor() ? '.prototype`' : '`')
);
}
foreach ($entry->{$kind} as $subentry) {
$subentry->member = $member;
if ($subentry->isAlias()) {
$result[] = MarkdownGenerator::interpolate('* <a href="##{hash}" class="alias">`#{member}#{separator}#{name}` -> `#{realName}`</a>', array(
'hash' => $subentry->hash,
'member' => $subentry->member,
'name' => $subentry->getName(),
'realName' => $subentry->owner->getName(),
'separator' => $subentry->separator
));
}
else {
$result[] = MarkdownGenerator::interpolate('* <a href="##{hash}">`#{member}#{separator}#{name}`</a>', $subentry);
}
}
}
}
}
array_push($result, $closeTag, $closeTag);
/*------------------------------------------------------------------------*/
// compile content
$compiling = false;
$result[] = $openTag;
if ($byCategory) {
foreach ($categories as $category => $entries) {
if ($compiling) {
$result[] = $closeTag;
} else {
$compiling = true;
}
if ($category != 'Methods' && $category != 'Properties') {
$category = '“' . $category . '” Methods';
}
array_push($result, $openTag, '## `' . $category . '`');
$this->addEntries($result, $entries);
}
}
else {
foreach ($api as $entry) {
// skip aliases
if ($entry->isAlias()) {
continue;
}
if ($compiling) {
$result[] = $closeTag;
} else {
$compiling = true;
}
// add root entry name
$member = $entry->member . $entry->getName();
array_push($result, $openTag, '## `' . $member . '`');
foreach (array($entry, 'static', 'plugin') as $kind) {
$subentries = is_string($kind) ? $entry->{$kind} : array($kind);
// add sub-entry name
if ($kind != 'static' && $entry->getType() != 'Object' &&
count($subentries) && $subentries[0] != $kind) {
if ($kind == 'plugin') {
$result[] = $closeTag;
}
array_push(
$result,
$openTag,
'## `' . $member . ($kind == 'plugin' ? '.prototype`' : '`')
);
}
$this->addEntries($result, $subentries);
}
}
}
// close tags add TOC link reference
array_push($result, $closeTag, $closeTag, '', ' [1]: #' . $toc . ' "Jump back to the TOC."');
// cleanup whitespace
return trim(preg_replace('/[\t ]+\n/', "\n", join($result, "\n")));
}
}
?>