'use strict';
const fs = require('fs');
const commentRegex = new RegExp('/\\*\\*([^*]|\\*[^/])*\\*/', 'smg');
const interfaceRegex = new RegExp('@interface\\s+(\\S+)\\s*');
const implementsRegex = new RegExp('.*@implements\\b.+\n');
const memberofRegex = new RegExp('@memberof\\s+(.*)\\s*');
const propertyRegex = new RegExp('@property\\s+\\{([^}]+)\\}', 'g');
const arrayTypeRegex = new RegExp('^Array\\.<(.+)>$');
const mapTypeRegex = new RegExp('^Object\\.<string,(.+)>$');
function fixPropertyType(typeName, interfaces) {
switch (typeName) {
case 'number':
case 'boolean':
case 'string':
case 'Uint8Array':
case 'null':
return typeName;
}
let match = arrayTypeRegex.exec(typeName);
if (match !== null) {
return `Array.<${fixPropertyType(match[1], interfaces)}>`;
}
match = mapTypeRegex.exec(typeName);
if (match !== null) {
return `Object.<string,${fixPropertyType(match[1], interfaces)}>`;
}
const tokens = typeName.split('.');
tokens[tokens.length - 1] = 'I' + tokens[tokens.length - 1];
const interfaceName = tokens.join('.');
if (!interfaces.has(interfaceName)) {
return typeName;
}
return `${typeName}|${tokens.join('.')}`;
}
function fixJsDoc(jsDoc, interfaces) {
if (jsDoc.indexOf('@interface') !== -1) {
jsDoc = jsDoc.replace(propertyRegex, (match, property) => {
const options = property
.split('|')
.map((property) => fixPropertyType(property, interfaces))
.join('|');
return `@property {${options}}`;
});
} else {
jsDoc = jsDoc.replace(implementsRegex, '');
}
return jsDoc;
}
exports.main = function (args ) {
const stdinBuffer = fs.readFileSync(0, 'utf-8');
const interfaces = new Set();
while (true) {
const match = commentRegex.exec(stdinBuffer);
if (match === null) {
break;
}
const jsDoc = match[0];
const memberofMatch = memberofRegex.exec(jsDoc);
const interfaceMatch = interfaceRegex.exec(jsDoc);
if (memberofMatch === null || interfaceMatch === null) {
continue;
}
interfaces.add(`${memberofMatch[1]}.${interfaceMatch[1]}`);
}
const chunks = [];
let lastIndex = 0;
while (true) {
const match = commentRegex.exec(stdinBuffer);
if (match === null) {
break;
}
chunks.push(stdinBuffer.slice(lastIndex, match.index));
chunks.push(fixJsDoc(match[0], interfaces));
lastIndex = match.index + match[0].length;
}
chunks.push(stdinBuffer.slice(lastIndex));
const finalSource = chunks
.join('')
.replace(
/(function create\(properties\)\s+{\n\s*)return new (\S+)(\(.*;\n\s*};)/gm,
(match, prelude, className, postlude) =>
`${prelude}return ${className}.fromObject${postlude}`,
);
fs.writeSync(1, finalSource);
};
exports.main(process.argv);