Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(docs): Autogenerated Aztec-nr reference docs #3481

Merged
merged 37 commits into from
Feb 22, 2024
Merged
Show file tree
Hide file tree
Changes from 11 commits
Commits
Show all changes
37 commits
Select commit Hold shift + click to select a range
e3b31b6
initial script
catmcgee Nov 30, 2023
0c42ed3
multiple line comment descriptions
catmcgee Dec 5, 2023
9b9b625
Merge branch 'master' into aztecnr-reference
catmcgee Dec 18, 2023
44df329
reference
catmcgee Jan 15, 2024
07c6b13
Merge branch 'master' into aztecnr-reference
catmcgee Feb 6, 2024
5a745d5
update script
catmcgee Feb 6, 2024
9cb59e9
kinda working
catmcgee Feb 6, 2024
6462e80
sidebar merge conflicts
catmcgee Feb 9, 2024
54bd296
Merge remote-tracking branch 'origin/master' into aztecnr-reference
catmcgee Feb 9, 2024
e4935e7
transcript.hpp
catmcgee Feb 9, 2024
5f88400
script
catmcgee Feb 9, 2024
8efe5ad
fix yarn start:dev:local
catmcgee Feb 12, 2024
6160d9b
add code block in functions
catmcgee Feb 12, 2024
92e6418
added some comments
catmcgee Feb 12, 2024
1edcd75
Merge branch 'master' into aztecnr-reference
catmcgee Feb 12, 2024
dd7a1a9
Merge branch 'master' into aztecnr-reference
catmcgee Feb 12, 2024
8e5b51d
Merge branch 'master' into aztecnr-reference
catmcgee Feb 12, 2024
a490da8
Merge remote-tracking branch 'origin/master' into aztecnr-reference
catmcgee Feb 13, 2024
0c8a8fe
Merge branch 'master' into aztecnr-reference
catmcgee Feb 13, 2024
cc7c599
Merge branch 'master' into aztecnr-reference
catmcgee Feb 14, 2024
5780de5
Merge branch 'master' into aztecnr-reference
catmcgee Feb 14, 2024
7799747
Merge branch 'master' into aztecnr-reference
catmcgee Feb 15, 2024
9990da1
Merge branch 'master' into aztecnr-reference
catmcgee Feb 15, 2024
579a042
woops
catmcgee Feb 15, 2024
2cd491c
update paths for ci
catmcgee Feb 15, 2024
36de06a
const -> let
catmcgee Feb 15, 2024
b4e5bd9
Merge branch 'master' into aztecnr-reference
catmcgee Feb 16, 2024
5eccc41
update paths
catmcgee Feb 16, 2024
a881a8b
Merge branch 'master' into aztecnr-reference
catmcgee Feb 16, 2024
ad8a686
Merge branch 'master' into aztecnr-reference
catmcgee Feb 16, 2024
8eaa5c2
Merge branch 'master' into aztecnr-reference
catmcgee Feb 16, 2024
5b48bcc
Merge remote-tracking branch 'origin/master' into aztecnr-reference
catmcgee Feb 22, 2024
5d15b9e
Merge branch 'master' into aztecnr-reference
signorecello Feb 22, 2024
a7dcd86
chore(docs): fix
signorecello Feb 22, 2024
f87af4a
fix?
signorecello Feb 22, 2024
b708225
fix?
signorecello Feb 22, 2024
6a371cc
Merge branch 'master' into aztecnr-reference
signorecello Feb 22, 2024
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
4 changes: 4 additions & 0 deletions docs/.gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -21,3 +21,7 @@
npm-debug.log*
yarn-debug.log*
yarn-error.log*

/docs/developers/contracts/references/aztec-nr

/src/preprocess/AztecnrReferenceAutogenStructure.json
signorecello marked this conversation as resolved.
Show resolved Hide resolved
2 changes: 1 addition & 1 deletion docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
"private": true,
"scripts": {
"docusaurus": "docusaurus",
"start": "yarn preprocess && yarn typedoc && docusaurus start --host 0.0.0.0",
"start": "yarn preprocess && yarn typedoc && node src/preprocess/generate_aztecnr_reference.js && docusaurus start --host 0.0.0.0",
"start:dev": "concurrently \"yarn preprocess:dev\" \"yarn typedoc:dev\" \"sleep 2 && docusaurus start --host 0.0.0.0\"",
"start:dev:local": "concurrently \"yarn preprocess:dev\" \"yarn typedoc:dev\" \"sleep 2 && docusaurus start\"",
"build": "./scripts/build.sh",
Expand Down
3 changes: 3 additions & 0 deletions docs/scripts/build.sh
Original file line number Diff line number Diff line change
Expand Up @@ -45,4 +45,7 @@ fi

# Now build the docsite
echo Building docsite...
echo "Generating Aztec.nr reference docs..."
node ./src/preprocess/generate_aztecnr_reference.js
echo "Generated Aztec.nr reference docs"
yarn preprocess && yarn typedoc && yarn docusaurus build
38 changes: 37 additions & 1 deletion docs/sidebars.js
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,37 @@

// @ts-check

const fs = require('fs');
const path = require('path');
// Load the structured documentation paths
const docsStructurePath = path.join(__dirname, '/src/preprocess/AztecnrReferenceAutogenStructure.json');
const docsStructure = JSON.parse(fs.readFileSync(docsStructurePath, 'utf8'));

// Function to recursively build sidebar items from the structured documentation
function buildSidebarItemsFromStructure(structure, basePath = '') {
const items = [];
for (const key in structure) {
if (key === '_docs') {
// Base case: add the docs
structure[key].forEach(doc => {
items.push(`${basePath}/${doc}`);
});
} else {
// Recursive case: process a subdirectory
const subItems = buildSidebarItemsFromStructure(structure[key], `${basePath}/${key}`);
items.push({
type: 'category',
label: key.charAt(0).toUpperCase() + key.slice(1), // Capitalize the label
items: subItems,
});
}
}
return items;
}

// Build sidebar for AztecNR documentation
const aztecNRSidebar = buildSidebarItemsFromStructure(docsStructure.AztecNR, 'developers/contracts/references/aztec-nr');

/** @type {import('@docusaurus/plugin-content-docs').SidebarsConfig} */
const sidebars = {
docsSidebar: [
Expand Down Expand Up @@ -440,6 +471,11 @@ const sidebars = {
"developers/contracts/references/portals/registry",
],
},
{
label: "Aztec.nr Reference",
type: "category",
items: aztecNRSidebar,
},
"developers/contracts/references/history_lib_reference",
"developers/contracts/references/slow_updates_tree",
],
Expand Down Expand Up @@ -596,4 +632,4 @@ const sidebars = {
],
};

module.exports = sidebars;
module.exports = sidebars;
277 changes: 277 additions & 0 deletions docs/src/preprocess/generate_aztecnr_reference.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,277 @@
const fs = require('fs');
const path = require('path');

function listNrFiles(dir, fileList = []) {
const files = fs.readdirSync(dir);
files.forEach(file => {
const filePath = path.join(dir, file);
const stat = fs.statSync(filePath);
if (stat.isDirectory()) {
listNrFiles(filePath, fileList);
} else if (filePath.endsWith('.nr') && !file.endsWith('lib.nr')) {
fileList.push(filePath);
}
});
return fileList;
}

function escapeHtml(unsafeText) {
if (!unsafeText) {
// Return an empty string or some default value if unsafeText is undefined or null
return '';
}
return unsafeText.replace(/</g, "&lt;").replace(/>/g, "&gt;");
}


function parseParameters(paramString) {
if (!paramString.trim()) {
return [];
}

return paramString.split(',').map(param => {
param = param.trim().replace(/[\[:;,.]$/g, '').replace(/^[\[:;,.]/g, ''); // Clean up start and end
let [paramName, type] = param.split(':').map(p => p.trim());
return { name: paramName, type: escapeHtml(type) };
});
}


function parseStruct(content) {
const structRegex = /struct (\w+)\s*{([\s\S]*?)}/g;
let match;
const structs = [];

while ((match = structRegex.exec(content)) !== null) {
const structName = match[1];
const fields = match[2].trim().split('\n').map(fieldLine => {
fieldLine = fieldLine.trim().replace(/,$/, '');
// Skip lines that are comments or do not contain a colon (indicating they are not field definitions)
if (!fieldLine.startsWith('//') && fieldLine.includes(':')) {
let [name, type] = fieldLine.split(/:\s*/);
return { name, type };
}
}).filter(field => field !== undefined); // Filter out undefined entries resulting from comments or invalid lines

let descriptionLines = [];
let lineIndex = content.lastIndexOf('\n', match.index - 1);
while (lineIndex >= 0) {
let endOfPreviousLine = content.lastIndexOf('\n', lineIndex - 1);
let line = content.substring(endOfPreviousLine + 1, lineIndex).trim();

if (line.startsWith('//') && !line.includes('docs:start:') && !line.includes('docs:end:')) {
descriptionLines.unshift(line.replace('//', '').trim());
} else if (!line.startsWith('//')) {
break;
}

lineIndex = endOfPreviousLine;
}

let description = descriptionLines.join(' ');
structs.push({ structName, fields, description });
}

return structs;
}

function parseFunctions(content) {
const functions = [];
const implRegex = /impl\s+(\w+)\s*{/g;
let implMatch;

while ((implMatch = implRegex.exec(content)) !== null) {
const structName = implMatch[1];
let braceDepth = 1;
let currentPos = implMatch.index + implMatch[0].length;

while (braceDepth > 0 && currentPos < content.length) {
if (content[currentPos] === '{') {
braceDepth++;
} else if (content[currentPos] === '}') {
braceDepth--;
}
currentPos++;
}

const implBlockContent = content.substring(implMatch.index, currentPos);
const methodRegex = /(?:pub )?fn (\w+)\((.*?)\)(?: -> (.*?))? {/g;
let methodMatch;

while ((methodMatch = methodRegex.exec(implBlockContent)) !== null) {
const name = methodMatch[1];
const params = parseParameters(methodMatch[2]);
const returnType = (methodMatch[3] || '').replace(/[\[:;,.]$/g, '').replace(/^[\[:;,.]/g, '');

let description = '';
let commentIndex = methodMatch.index;
while (commentIndex >= 0) {
const commentMatch = implBlockContent.substring(0, commentIndex).match(/\/\/\s*(.*)\n\s*$/);
if (commentMatch && !commentMatch[1].includes('docs:start:') && !commentMatch[1].includes('docs:end:')) {
description = commentMatch[1] + (description ? ' ' + description : '');
commentIndex = commentMatch.index - 1;
} else {
break;
}
}

functions.push({ structName, name, params, returnType, description, isMethod: true });
}
}

const standaloneFunctionRegex = /(?:pub\s+)?fn\s+(\w+)(?:<.*?>)?\s*\((.*?)\)\s*(?:->\s*(.*?))?\s*{/g;
let standaloneFunctionMatch;
while ((standaloneFunctionMatch = standaloneFunctionRegex.exec(content)) !== null) {
const name = standaloneFunctionMatch[1];

if (!functions.some(f => f.name === name && f.isMethod)) {
const params = parseParameters(standaloneFunctionMatch[2]);
const returnType = (standaloneFunctionMatch[3] || '').replace(/[\[:;,.]$/g, '').replace(/^[\[:;,.]/g, '');

let description = '';
const descriptionMatch = content.substring(0, standaloneFunctionMatch.index).match(/\/\/\s*(.*)\n\s*$/);
if (descriptionMatch) {
const precedingText = content.substring(0, descriptionMatch.index);
if (!precedingText.includes('docs:start:') && !precedingText.includes('docs:end:')) {
description = descriptionMatch[1];
}
}

functions.push({ name, params, returnType, description, isMethod: false });
}
}

return functions;
}

function generateMarkdown(structs, functions) {
let markdown = '';

structs.forEach(structInfo => {
if (structInfo) {
markdown += `# ${escapeHtml(structInfo.structName)}\n\n`;

if (structInfo.description) {
markdown += `${escapeHtml(structInfo.description)}\n\n`;
}

markdown += `## Fields\n`;
markdown += `| Field | Type |\n| --- | --- |\n`;
structInfo.fields.forEach(field => {
if (field && field.type) {
const cleanType = escapeHtml(field.type.replace(/[\[:;,]$/g, '').replace(/^[\[:;,]/g, ''));
const fieldName = escapeHtml(field.name.replace(/[:;]/g, ''));
markdown += `| ${fieldName} | ${cleanType} |\n`;
}
});
markdown += '\n';

// Generate markdown for methods of this struct
const methods = functions.filter(f => f.isMethod && f.structName === escapeHtml(structInfo.structName));
if (methods.length > 0) {
markdown += `## Methods\n\n`;
methods.forEach(func => {
markdown += `### ${escapeHtml(func.name)}\n\n`;
if (func.description) {
markdown += `${escapeHtml(func.description)}\n\n`;
}

if (func.params.length > 0) {
markdown += `#### Parameters\n`;
markdown += `| Name | Type |\n| --- | --- |\n`;
func.params.forEach(({ name, type }) => {
markdown += `| ${escapeHtml(name)} | ${escapeHtml(type)} |\n`;
});
} else {
markdown += `#### Parameters\nTakes no parameters.\n\n`;
}

if (func.returnType) {
markdown += `\n#### Returns\n`;
markdown += `| Type |\n| --- |\n`;
markdown += `| ${escapeHtml(func.returnType)} |\n`;
}
markdown += '\n';
});
}

}
});

// Generate markdown for standalone functions
const standaloneFunctions = functions.filter(f => !f.isMethod);
if (standaloneFunctions.length > 0) {
markdown += `## Standalone Functions\n\n`;
standaloneFunctions.forEach(func => {
markdown += `### ${escapeHtml(func.name)}\n\n`;
if (func.description) {
markdown += `${escapeHtml(func.description)}\n\n`;
}
if (func.params.length > 0) {
markdown += `#### Parameters\n`;
markdown += `| Name | Type |\n| --- | --- |\n`;
func.params.forEach(({ name, type }) => {
markdown += `| ${escapeHtml(name)} | ${escapeHtml(type)} |\n`;
});
} else {
markdown += `#### Parameters\nTakes no parameters.\n\n`;
}
if (func.returnType) {
markdown += `\n#### Returns\n`;
markdown += `| Type |\n| --- |\n`;
markdown += `| ${escapeHtml(func.returnType)} |\n`;
}
markdown += '\n';
});
}

return markdown;
}

function processFiles(baseDir, outputBaseDir) {
const nrFiles = listNrFiles(baseDir);
let docStructure = {}; // To hold structured documentation paths

nrFiles.forEach(filePath => {

const content = fs.readFileSync(filePath, 'utf8');
const structs = parseStruct(content);
const functions = parseFunctions(content);

if (structs.length === 0 && functions.length === 0) {
return;
}

const markdown = generateMarkdown(structs, functions);

const relativePath = path.relative(baseDir, filePath);
const adjustedPath = relativePath.replace('/src', '').replace(/\.nr$/, '.md');
const outputFilePath = path.join(outputBaseDir, adjustedPath);

fs.mkdirSync(path.dirname(outputFilePath), { recursive: true });
fs.writeFileSync(outputFilePath, markdown);

// Adjusted to populate docStructure for JSON
const docPathForJson = adjustedPath.replace(/\\/g, '/').replace('.md', '');
const parts = docPathForJson.split('/');
let current = docStructure;

for (let i = 0; i < parts.length - 1; i++) {
current[parts[i]] = current[parts[i]] || {};
current = current[parts[i]];
}

current._docs = current._docs || [];
current._docs.push(parts[parts.length - 1]);
});

// Write structured documentation paths to JSON
const outputPath = path.join(__dirname, 'AztecnrReferenceAutogenStructure.json');
fs.writeFileSync(outputPath, JSON.stringify({ AztecNR: docStructure }, null, 2));
}

const baseDir = path.resolve(__dirname, '../../../yarn-project/aztec-nr');
const outputBaseDir = path.resolve(__dirname, '../../docs/developers/contracts/references/aztec-nr');

processFiles(baseDir, outputBaseDir);

Loading