mirror of
https://github.com/processing/p5.js.git
synced 2025-12-08 17:36:35 +00:00
1. Store argument types to increase speed a bit and to prevent repetive logging 2. Create new json file parameterData.json from data.json and use it for the FES instead so as to reduce library size
324 lines
8.9 KiB
JavaScript
324 lines
8.9 KiB
JavaScript
const marked = require('marked');
|
|
|
|
const DocumentedMethod = require('./documented-method');
|
|
|
|
function smokeTestMethods(data) {
|
|
data.classitems.forEach(function(classitem) {
|
|
if (classitem.itemtype === 'method') {
|
|
new DocumentedMethod(classitem);
|
|
|
|
if (
|
|
classitem.access !== 'private' &&
|
|
classitem.file.substr(0, 3) === 'src' &&
|
|
classitem.name &&
|
|
!classitem.example
|
|
) {
|
|
console.log(
|
|
classitem.file +
|
|
':' +
|
|
classitem.line +
|
|
': ' +
|
|
classitem.itemtype +
|
|
' ' +
|
|
classitem.class +
|
|
'.' +
|
|
classitem.name +
|
|
' missing example'
|
|
);
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
function cleanExamples(data) {
|
|
data.classitems.forEach(function(classitem) {
|
|
if (classitem.itemtype === 'method' && classitem.example) {
|
|
classitem.example = classitem.example.map(i =>
|
|
i.replace(/[^\n]*\/\/\s*prettier-ignore.*\r?\n/g, '')
|
|
);
|
|
}
|
|
});
|
|
}
|
|
|
|
function mergeOverloadedMethods(data) {
|
|
let methodsByFullName = {};
|
|
let paramsForOverloadedMethods = {};
|
|
|
|
let consts = (data.consts = {});
|
|
|
|
data.classitems = data.classitems.filter(function(classitem) {
|
|
if (classitem.access === 'private') {
|
|
return false;
|
|
}
|
|
|
|
const itemClass = data.classes[classitem.class];
|
|
if (!itemClass || itemClass.private) {
|
|
return false;
|
|
}
|
|
|
|
let methodConsts = {};
|
|
|
|
let fullName, method;
|
|
|
|
var assertEqual = function(a, b, msg) {
|
|
if (a !== b) {
|
|
throw new Error(
|
|
'for ' +
|
|
fullName +
|
|
'() defined in ' +
|
|
classitem.file +
|
|
':' +
|
|
classitem.line +
|
|
', ' +
|
|
msg +
|
|
' (' +
|
|
JSON.stringify(a) +
|
|
' !== ' +
|
|
JSON.stringify(b) +
|
|
')'
|
|
);
|
|
}
|
|
};
|
|
|
|
var extractConsts = function(param) {
|
|
if (!param.type) {
|
|
console.log(param);
|
|
}
|
|
if (param.type.split('|').indexOf('Constant') >= 0) {
|
|
let match;
|
|
if (classitem.name === 'endShape' && param.name === 'mode') {
|
|
match = 'CLOSE';
|
|
} else {
|
|
const constantRe = /either\s+(?:[A-Z0-9_]+\s*,?\s*(?:or)?\s*)+/g;
|
|
const execResult = constantRe.exec(param.description);
|
|
match = execResult && execResult[0];
|
|
if (!match) {
|
|
throw new Error(
|
|
classitem.file +
|
|
':' +
|
|
classitem.line +
|
|
', Constant-typed parameter ' +
|
|
fullName +
|
|
'(...' +
|
|
param.name +
|
|
'...) is missing valid value enumeration. ' +
|
|
'See inline_documentation.md#specify-parameters.'
|
|
);
|
|
}
|
|
}
|
|
if (match) {
|
|
const reConst = /[A-Z0-9_]+/g;
|
|
let matchConst;
|
|
while ((matchConst = reConst.exec(match)) !== null) {
|
|
methodConsts[matchConst] = true;
|
|
}
|
|
}
|
|
}
|
|
};
|
|
|
|
var processOverloadedParams = function(params) {
|
|
let paramNames;
|
|
|
|
if (!(fullName in paramsForOverloadedMethods)) {
|
|
paramsForOverloadedMethods[fullName] = {};
|
|
}
|
|
|
|
paramNames = paramsForOverloadedMethods[fullName];
|
|
|
|
params.forEach(function(param) {
|
|
const origParam = paramNames[param.name];
|
|
|
|
if (origParam) {
|
|
assertEqual(
|
|
origParam.type,
|
|
param.type,
|
|
'types for param "' +
|
|
param.name +
|
|
'" must match ' +
|
|
'across all overloads'
|
|
);
|
|
assertEqual(
|
|
param.description,
|
|
'',
|
|
'description for param "' +
|
|
param.name +
|
|
'" should ' +
|
|
'only be defined in its first use; subsequent ' +
|
|
'overloads should leave it empty'
|
|
);
|
|
} else {
|
|
paramNames[param.name] = param;
|
|
extractConsts(param);
|
|
}
|
|
});
|
|
|
|
return params;
|
|
};
|
|
|
|
if (classitem.itemtype && classitem.itemtype === 'method') {
|
|
fullName = classitem.class + '.' + classitem.name;
|
|
if (fullName in methodsByFullName) {
|
|
// It's an overloaded version of a method that we've already
|
|
// indexed. We need to make sure that we don't list it multiple
|
|
// times in our index pages and such.
|
|
|
|
method = methodsByFullName[fullName];
|
|
|
|
assertEqual(
|
|
method.file,
|
|
classitem.file,
|
|
'all overloads must be defined in the same file'
|
|
);
|
|
assertEqual(
|
|
method.module,
|
|
classitem.module,
|
|
'all overloads must be defined in the same module'
|
|
);
|
|
assertEqual(
|
|
method.submodule,
|
|
classitem.submodule,
|
|
'all overloads must be defined in the same submodule'
|
|
);
|
|
assertEqual(
|
|
classitem.description || '',
|
|
'',
|
|
'additional overloads should have no description'
|
|
);
|
|
|
|
var makeOverload = function(method) {
|
|
const overload = {
|
|
line: method.line,
|
|
params: processOverloadedParams(method.params || [])
|
|
};
|
|
// TODO: the doc renderer assumes (incorrectly) that
|
|
// these are the same for all overrides
|
|
if (method.static) overload.static = method.static;
|
|
if (method.chainable) overload.chainable = method.chainable;
|
|
if (method.return) overload.return = method.return;
|
|
return overload;
|
|
};
|
|
|
|
if (!method.overloads) {
|
|
method.overloads = [makeOverload(method)];
|
|
delete method.params;
|
|
}
|
|
method.overloads.push(makeOverload(classitem));
|
|
return false;
|
|
} else {
|
|
if (classitem.params) {
|
|
classitem.params.forEach(function(param) {
|
|
extractConsts(param);
|
|
});
|
|
}
|
|
methodsByFullName[fullName] = classitem;
|
|
}
|
|
|
|
Object.keys(methodConsts).forEach(constName =>
|
|
(consts[constName] || (consts[constName] = [])).push(fullName)
|
|
);
|
|
}
|
|
return true;
|
|
});
|
|
}
|
|
|
|
// build a copy of data.json for the FES, restructured for object lookup on
|
|
// classitems and removing all the parts not needed by the FES
|
|
function buildParamDocs(docs) {
|
|
let newClassItems = {};
|
|
// the fields we need for the FES, discard everything else
|
|
let allowed = new Set(['name', 'class', 'module', 'params', 'overloads']);
|
|
for (let classitem of docs.classitems) {
|
|
if (classitem.name && classitem.class) {
|
|
for (let key in classitem) {
|
|
if (!allowed.has(key)) {
|
|
delete classitem[key];
|
|
}
|
|
}
|
|
if (classitem.hasOwnProperty('overloads')) {
|
|
for (let overload of classitem.overloads) {
|
|
// remove line number and return type
|
|
if (overload.line) {
|
|
delete overload.line;
|
|
}
|
|
|
|
if (overload.return) {
|
|
delete overload.return;
|
|
}
|
|
}
|
|
}
|
|
if (!newClassItems[classitem.class]) {
|
|
newClassItems[classitem.class] = {};
|
|
}
|
|
|
|
newClassItems[classitem.class][classitem.name] = classitem;
|
|
}
|
|
}
|
|
|
|
let fs = require('fs');
|
|
let path = require('path');
|
|
let out = fs.createWriteStream(
|
|
path.join(process.cwd(), 'docs', 'parameterData.json'),
|
|
{
|
|
flags: 'w',
|
|
mode: '0644'
|
|
}
|
|
);
|
|
out.write(JSON.stringify(newClassItems, null, 2));
|
|
out.end();
|
|
}
|
|
|
|
function renderItemDescriptionsAsMarkdown(item) {
|
|
if (item.description) {
|
|
item.description = marked(item.description);
|
|
}
|
|
if (item.params) {
|
|
item.params.forEach(renderItemDescriptionsAsMarkdown);
|
|
}
|
|
}
|
|
|
|
function renderDescriptionsAsMarkdown(data) {
|
|
Object.keys(data.modules).forEach(function(moduleName) {
|
|
renderItemDescriptionsAsMarkdown(data.modules[moduleName]);
|
|
});
|
|
Object.keys(data.classes).forEach(function(className) {
|
|
renderItemDescriptionsAsMarkdown(data.classes[className]);
|
|
});
|
|
data.classitems.forEach(function(classitem) {
|
|
renderItemDescriptionsAsMarkdown(classitem);
|
|
});
|
|
}
|
|
|
|
module.exports = (data, options) => {
|
|
data.classitems
|
|
.filter(
|
|
ci => !ci.itemtype && (ci.params || ci.return) && ci.access !== 'private'
|
|
)
|
|
.forEach(ci => {
|
|
console.error(ci.file + ':' + ci.line + ': unnamed public member');
|
|
});
|
|
|
|
Object.keys(data.classes)
|
|
.filter(k => data.classes[k].access === 'private')
|
|
.forEach(k => delete data.classes[k]);
|
|
|
|
renderDescriptionsAsMarkdown(data);
|
|
mergeOverloadedMethods(data);
|
|
smokeTestMethods(data);
|
|
cleanExamples(data);
|
|
buildParamDocs(JSON.parse(JSON.stringify(data)));
|
|
};
|
|
|
|
module.exports.mergeOverloadedMethods = mergeOverloadedMethods;
|
|
module.exports.renderDescriptionsAsMarkdown = renderDescriptionsAsMarkdown;
|
|
|
|
module.exports.register = (Handlebars, options) => {
|
|
Handlebars.registerHelper('root', function(context, options) {
|
|
// if (this.language === 'en') {
|
|
// return '';
|
|
// } else {
|
|
// return '/'+this.language;
|
|
// }
|
|
return window.location.pathname;
|
|
});
|
|
};
|