Skip to content
This repository has been archived by the owner on Dec 31, 2017. It is now read-only.

defer resolving the annotated object. #82

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
76 changes: 75 additions & 1 deletion lib/exporter/dojov1.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,12 @@
define([ '../Module', '../Value', './util', '../console', '../node!fs' ], function (Module, Value, util, console, fs) {
define([
'dojo/string',
'../Module',
'../Value',
'./util',
'../console',
'dojo/node!fs',
], function (stringUtil, Module, Value, util, console, fs) {

/**
* Takes information from metadata stored alongside a Value and adds it to the output.
* @param node The node to add metadata to.
Expand Down Expand Up @@ -34,6 +42,66 @@ define([ '../Module', '../Value', './util', '../console', '../node!fs' ], functi
}
}

/**
* Given metadata with a type annotation, attempt to resolve the annotated type as an object and (hackily) apply
* information about the object’s default properties to the metadata description property.
*/
function processTypeAnnotation(/**Object*/ metadata) {
if (!metadata.type || typeof metadata.type === 'string') {
return;
}

var propertyTemplate = '<li>${key}${type}${summary}</li>',
annotationObject = metadata.type,
additionalDescription = '';

if (annotationObject.relatedModule) {
metadata.type = annotationObject.relatedModule.id;
return;
}

metadata.type = 'Object';
additionalDescription += '<p>' + (metadata.description ?
'The following properties are supported:' :
'An object with the following properties:') + '</p><ul>';

(function readProperties(object) {
var propertyMetadata,
properties = object.properties,
k;

// if the annotationObject is a function, we don't want to pick up any properties apart
// from what's on the prototype.
if (object.type === 'function') {
if (_hasOwnProperty.call(properties, 'prototype')) {
readProperties(properties.prototype);
}
return;
}

for (k in properties) {
if (_hasOwnProperty.call(properties, k)) {
// Type descriptor could be a plain JS object, or could be a constructor. It is often the
// latter.
if (k === 'prototype') {
readProperties(properties[k]);
}
// Filter out built-ins and constructor properties which come from dojo/_base/declare
else if (k !== 'constructor' && properties[k].file) {
propertyMetadata = properties[k].metadata;
additionalDescription += stringUtil.substitute(propertyTemplate, {
key: k,
type: propertyMetadata.type ? ' (' + propertyMetadata.type + (propertyMetadata.isOptional ? ', optional' : '') + ')' : '',
summary: propertyMetadata.summary ? ': ' + propertyMetadata.summary : ''
});
}
}
}
}(annotationObject));

metadata.description = (metadata.description || '') + additionalDescription + '</ul>';
}

/**
* Takes an array of return Values and processes it for return types, discarding all
* duplicates, and applies the resulting list of properties to the node given in returnsNode.
Expand Down Expand Up @@ -67,6 +135,9 @@ define([ '../Module', '../Value', './util', '../console', '../node!fs' ], functi
i;

for (i = 0; (parameter = property.parameters[i]); ++i) {
if (typeof parameter.metadata.type !== 'string') {
processTypeAnnotation(parameter.metadata);
}
parameterType = parameter.metadata.type || parameter.type || 'unknown';
parameterNode = parametersNode.createNode('parameter', {
name: parameter.name,
Expand Down Expand Up @@ -105,6 +176,9 @@ define([ '../Module', '../Value', './util', '../console', '../node!fs' ], functi
propertyNode;

function makePropertyObject(name, value) {
if (typeof value.metadata.type !== 'string') {
processTypeAnnotation(value.metadata);
}
var object = {
name: name,
scope: scope,
Expand Down
52 changes: 8 additions & 44 deletions lib/processor/dojodoc.js
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ define([
if (source[k] instanceof Array && destination[k] instanceof Array) {
destination[k] = destination[k].concat(source[k]);
}
else if (k === 'type') {
else if (k === 'type' && typeof source[k] === 'string') {
destination[k] = source[k].replace(optionalTypeRe, '');
}
else if (typeof source[k] !== 'string' || trim(source[k])) {
Expand Down Expand Up @@ -113,60 +113,24 @@ define([
}

/**
* Given metadata with a type annotation, attempt to resolve the annotated type as an object and (hackily) apply
* information about the object’s default properties to the metadata description property.
* TODO: This should really end up happening in the dojov1 exporter instead.
* Given metadata with a type annotation, attempt to resolve the annotated type as an object and
* provide that object to the exporter as the type property of the metadata.
*/
function processTypeAnnotation(/**Object*/ metadata) {
if (!metadata.type) {
return;
}

var propertyTemplate = '\n* ${key}${type}${summary}',
annotationObject = env.scope.getVariable(metadata.type.replace(/[^\w$\.]+$/g, '').split('.')),
additionalDescription = '';
var annotationObject = env.scope.getVariable(metadata.type.replace(/[^\w$\.]+$/g, '').split('.'));

if (!annotationObject || annotationObject.type === Value.TYPE_UNDEFINED || /* not a built-in */ !annotationObject.file) {
return;
}

if (annotationObject.relatedModule) {
metadata.type = annotationObject.relatedModule.id;
return;
}

// TODO: The fact that evaluate exists on annotation objects seems to indicate that we’re failing to
// evaluate all function expressions; this might be an issue
annotationObject.evaluate && annotationObject.evaluate();

metadata.type = 'Object';
additionalDescription += metadata.description ?
'\n\nThe following properties are supported:\n' :
'An object with the following properties:\n';

(function readProperties(object) {
var propertyMetadata;
for (var k in object.properties) {
if (_hasOwnProperty.call(object.properties, k)) {
// Type descriptor could be a plain JS object, or could be a constructor. It is often the
// latter.
if (k === 'prototype') {
readProperties(object.properties[k]);
}
// Filter out built-ins and constructor properties which come from dojo/_base/declare
else if (k !== 'constructor' && object.properties[k].file) {
propertyMetadata = object.properties[k].metadata;
additionalDescription += stringUtil.substitute(propertyTemplate, {
key: k,
type: propertyMetadata.type ? ' (' + propertyMetadata.type + (propertyMetadata.isOptional ? ', optional' : '') + ')' : '',
summary: propertyMetadata.summary ? ': ' + propertyMetadata.summary : ''
});
}
}
}
}(annotationObject));

metadata.description = (metadata.description || '') + parseMarkdown(additionalDescription);
// defer resolving this to do it in the exporter. annotationObject might be the return
// value of the module currently being processed and in that case it won't have been tagged
// with a relatedModule yet.
metadata.type = annotationObject;
}

/**
Expand Down