Spaces:
Sleeping
Sleeping
| /* | |
| * Copyright (C) 2024-present Puter Technologies Inc. | |
| * | |
| * This file is part of Puter. | |
| * | |
| * Puter is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU Affero General Public License as published | |
| * by the Free Software Foundation, either version 3 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU Affero General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU Affero General Public License | |
| * along with this program. If not, see <https://www.gnu.org/licenses/>. | |
| */ | |
| const fs = require("fs"); | |
| const path_ = require("path"); | |
| const rootdir = path_.resolve(process.argv[2] ?? '.'); | |
| const parser = require('@babel/parser'); | |
| const traverse = require('@babel/traverse').default; | |
| const { ModuleDoc } = require("./defs"); | |
| const processors = require("./processors"); | |
| const doc_module = new ModuleDoc(); | |
| const handle_file = (code, context) => { | |
| const ast = parser.parse(code); | |
| const traverse_callbacks = {}; | |
| for ( const processor of processors ) { | |
| if ( processor.match(context) ) { | |
| for ( const key in processor.traverse ) { | |
| if ( ! traverse_callbacks[key] ) { | |
| traverse_callbacks[key] = []; | |
| } | |
| traverse_callbacks[key].push(processor.traverse[key]); | |
| } | |
| } | |
| } | |
| for ( const key in traverse_callbacks ) { | |
| traverse(ast, { | |
| [key] (path) { | |
| context.skip = false; | |
| for ( const callback of traverse_callbacks[key] ) { | |
| callback(path, context); | |
| if ( context.skip ) return; | |
| } | |
| } | |
| }); | |
| } | |
| } | |
| // Module and class files | |
| { | |
| const files = fs.readdirSync(rootdir); | |
| for ( const file of files ) { | |
| const stat = fs.statSync(path_.join(rootdir, file)); | |
| if ( stat.isDirectory() ) { | |
| continue; | |
| } | |
| if ( ! file.endsWith('.js') ) continue; | |
| const type = | |
| file.endsWith('Service.js') ? 'service' : | |
| file.endsWith('Module.js') ? 'module' : | |
| null; | |
| if ( type === null ) continue; | |
| console.log('file', file); | |
| const code = fs.readFileSync(path_.join(rootdir, file), 'utf8'); | |
| const firstLine = code.slice(0, code.indexOf('\n')); | |
| let metadata = {}; | |
| const METADATA_PREFIX = '// METADATA // '; | |
| if ( firstLine.startsWith(METADATA_PREFIX) ) { | |
| metadata = JSON.parse(firstLine.slice(METADATA_PREFIX.length)); | |
| } | |
| const context = { | |
| metadata, | |
| type, | |
| doc_module, | |
| filename: file, | |
| }; | |
| handle_file(code, context); | |
| } | |
| } | |
| // Library files | |
| if ( fs.existsSync(path_.join(rootdir, 'lib')) ) { | |
| const files = fs.readdirSync(path_.join(rootdir, 'lib')); | |
| for ( const file of files ) { | |
| if ( file.startsWith('_') ) continue; | |
| const code = fs.readFileSync(path_.join(rootdir, 'lib', file), 'utf8'); | |
| const firstLine = code.slice(0, code.indexOf('\n')); | |
| let metadata = {}; | |
| const METADATA_PREFIX = '// METADATA // '; | |
| if ( firstLine.startsWith(METADATA_PREFIX) ) { | |
| metadata = JSON.parse(firstLine.slice(METADATA_PREFIX.length)); | |
| } | |
| const doc_item = doc_module.add_lib(); | |
| doc_item.name = metadata.def ?? file.slice(0, -3); | |
| const context = { | |
| metadata, | |
| type: 'lib', | |
| doc_module, | |
| doc_item, | |
| filename: file, | |
| }; | |
| handle_file(code, context); | |
| } | |
| } | |
| const outfile = path_.join(rootdir, 'README.md'); | |
| const out = doc_module.toMarkdown(); | |
| fs.writeFileSync(outfile, out); |