apisurf
Version:
Analyze API surface changes between npm package versions to catch breaking changes
57 lines (56 loc) • 2.14 kB
JavaScript
/**
* Parse interface definition from source lines
*/
export function parseInterfaceDefinition(lines, startIndex, name) {
const properties = [];
let braceCount = 0;
let inInterface = false;
for (let i = startIndex; i < lines.length; i++) {
const line = lines[i].trim();
// Count the brace level before parsing
const prevBraceCount = braceCount;
// Count braces
const openBraces = (line.match(/{/g) || []).length;
const closeBraces = (line.match(/}/g) || []).length;
if (openBraces > 0) {
braceCount += openBraces;
if (!inInterface) {
inInterface = true;
}
}
// Only parse properties at the top level (braceCount === 1 BEFORE counting this line's braces)
if (inInterface && prevBraceCount === 1 && !line.startsWith('}')) {
// Match properties like: propertyName: type; or propertyName?: type;
// This includes properties with object types like: user: { ... }
const propMatch = line.match(/^\s*(\w+)(\?)?:\s*/);
if (propMatch && !line.match(/^\s*\w+\s*\(/)) { // Not a method
properties.push({
name: propMatch[1],
required: !propMatch[2]
});
}
// Match method signatures like: methodName(): void;
else if (line.match(/^\s*(\w+)(\?)?\s*\(/)) {
const methodMatch = line.match(/^\s*(\w+)(\?)?\s*\(/);
if (methodMatch) {
properties.push({
name: methodMatch[1],
required: !methodMatch[2]
});
}
}
}
if (closeBraces > 0) {
braceCount -= closeBraces;
if (braceCount === 0) {
break;
}
}
}
return {
name,
kind: 'interface',
extendedProperties: properties,
signature: `export interface ${name} { ${properties.map(p => `${p.name}${p.required ? '' : '?'}: any`).join('; ')} }`
};
}