Skip to content

Commit

Permalink
feat: legacy json generator (#142)
Browse files Browse the repository at this point in the history
Co-authored-by: flakey5 <73616808+flakey5@users.noreply.github.com>
Co-authored-by: Claudio W <cwunder@gnome.org>
  • Loading branch information
3 people authored Nov 25, 2024
1 parent 4963da2 commit 8f40d5c
Show file tree
Hide file tree
Showing 21 changed files with 1,136 additions and 32 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,6 @@ Options:
-o, --output <path> Specify the relative or absolute output directory
-v, --version <semver> Specify the target version of Node.js, semver compliant (default: "v22.6.0")
-c, --changelog <url> Specify the path (file: or https://) to the CHANGELOG.md file (default: "https://raw.githubusercontent.com/nodejs/node/HEAD/CHANGELOG.md")
-t, --target [mode...] Set the processing target modes (choices: "json-simple", "legacy-html", "legacy-html-all", "man-page")
-t, --target [mode...] Set the processing target modes (choices: "json-simple", "legacy-html", "legacy-html-all", "man-page", "legacy-json", "legacy-json-all")
-h, --help display help for command
```
4 changes: 2 additions & 2 deletions shiki.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ export default {
// Only register the languages that the API docs use
// and override the JavaScript language with the aliases
langs: [
{ ...javaScriptLanguage[0], aliases: ['mjs', 'cjs', 'js'] },
...httpLanguage,
...jsonLanguage,
...typeScriptLanguage,
...shellScriptLanguage,
Expand All @@ -40,7 +40,7 @@ export default {
...diffLanguage,
...cLanguage,
...cPlusPlusLanguage,
...httpLanguage,
...coffeeScriptLanguage,
{ ...javaScriptLanguage[0], aliases: ['mjs', 'cjs', 'js'] },
],
};
15 changes: 12 additions & 3 deletions src/constants.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,14 @@ export const DOC_API_SLUGS_REPLACEMENTS = [
// is a specific type of API Doc entry (e.g., Event, Class, Method, etc)
// and to extract the inner content of said Heading to be used as the API doc entry name
export const DOC_API_HEADING_TYPES = [
{ type: 'method', regex: /^`?([A-Z]\w+(?:\.[A-Z]\w+)*\.\w+)\([^)]*\)`?$/i },
{
type: 'method',
regex:
// Group 1: foo[bar]()
// Group 2: foo.bar()
// Group 3: foobar()
/^`?(?:\w*(?:(\[[^\]]+\])|(?:\.(\w+)))|(\w+))\([^)]*\)`?$/i,
},
{ type: 'event', regex: /^Event: +`?['"]?([^'"]+)['"]?`?$/i },
{
type: 'class',
Expand All @@ -71,11 +78,13 @@ export const DOC_API_HEADING_TYPES = [
},
{
type: 'classMethod',
regex: /^Static method: +`?([A-Z]\w+(?:\.[A-Z]\w+)*\.\w+)\([^)]*\)`?$/i,
regex:
/^Static method: +`?[A-Z]\w+(?:\.[A-Z]\w+)*(?:(\[\w+\.\w+\])|\.(\w+))\([^)]*\)`?$/i,
},
{
type: 'property',
regex: /^(?:Class property: +)?`?([A-Z]\w+(?:\.[A-Z]\w+)*\.\w+)`?$/i,
regex:
/^(?:Class property: +)?`?[A-Z]\w+(?:\.[A-Z]\w+)*(?:(\[\w+\.\w+\])|\.(\w+))`?$/i,
},
];

Expand Down
4 changes: 4 additions & 0 deletions src/generators/index.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -4,10 +4,14 @@ import jsonSimple from './json-simple/index.mjs';
import legacyHtml from './legacy-html/index.mjs';
import legacyHtmlAll from './legacy-html-all/index.mjs';
import manPage from './man-page/index.mjs';
import legacyJson from './legacy-json/index.mjs';
import legacyJsonAll from './legacy-json-all/index.mjs';

export default {
'json-simple': jsonSimple,
'legacy-html': legacyHtml,
'legacy-html-all': legacyHtmlAll,
'man-page': manPage,
'legacy-json': legacyJson,
'legacy-json-all': legacyJsonAll,
};
2 changes: 0 additions & 2 deletions src/generators/legacy-html/assets/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -165,8 +165,6 @@

let code = '';

console.log(parentNode);

if (flavorToggle) {
if (flavorToggle.checked) {
code = parentNode.querySelector('.mjs').textContent;
Expand Down
68 changes: 68 additions & 0 deletions src/generators/legacy-json-all/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
'use strict';

import { writeFile } from 'node:fs/promises';
import { join } from 'node:path';

/**
* This generator consolidates data from the `legacy-json` generator into a single
* JSON file (`all.json`).
*
* @typedef {Array<import('../legacy-json/types.d.ts').Section>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, import('./types.d.ts').Output>}
*/
export default {
name: 'legacy-json-all',

version: '1.0.0',

description:
'Generates the `all.json` file from the `legacy-json` generator, which includes all the modules in one single file.',

dependsOn: 'legacy-json',

/**
* Generates the legacy JSON `all.json` file.
*
* @param {Input} input
* @param {Partial<GeneratorOptions>} options
*/
async generate(input, { output }) {
/**
* The consolidated output object that will contain
* combined data from all sections in the input.
*
* @type {import('./types.d.ts').Output}
*/
const generatedValue = {
miscs: [],
modules: [],
classes: [],
globals: [],
methods: [],
};

const propertiesToCopy = [
'miscs',
'modules',
'classes',
'globals',
'methods',
];

input.forEach(section => {
// Copy the relevant properties from each section into our output
propertiesToCopy.forEach(property => {
if (section[property]) {
generatedValue[property].push(...section[property]);
}
});
});

if (output) {
await writeFile(join(output, 'all.json'), JSON.stringify(generatedValue));
}

return generatedValue;
},
};
14 changes: 14 additions & 0 deletions src/generators/legacy-json-all/types.d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import {
MiscSection,
Section,
SignatureSection,
ModuleSection,
} from '../legacy-json/types';

export interface Output {
miscs: Array<MiscSection>;
modules: Array<Section>;
classes: Array<SignatureSection>;
globals: Array<ModuleSection | { type: 'global' }>;
methods: Array<SignatureSection>;
}
36 changes: 36 additions & 0 deletions src/generators/legacy-json/constants.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// Grabs a method's return value
export const RETURN_EXPRESSION = /^returns?\s*:?\s*/i;

// Grabs a method's name
export const NAME_EXPRESSION = /^['`"]?([^'`": {]+)['`"]?\s*:?\s*/;

// Denotes a method's type
export const TYPE_EXPRESSION = /^\{([^}]+)\}\s*/;

// Checks if there's a leading hyphen
export const LEADING_HYPHEN = /^-\s*/;

// Grabs the default value if present
export const DEFAULT_EXPRESSION = /\s*\*\*Default:\*\*\s*([^]+)$/i;

// Grabs the parameters from a method's signature
// ex/ 'new buffer.Blob([sources[, options]])'.match(PARAM_EXPRESSION) === ['([sources[, options]])', '[sources[, options]]']
export const PARAM_EXPRESSION = /\((.+)\);?$/;

// The plurals associated with each section type.
export const SECTION_TYPE_PLURALS = {
module: 'modules',
misc: 'miscs',
class: 'classes',
method: 'methods',
property: 'properties',
global: 'globals',
example: 'examples',
ctor: 'signatures',
classMethod: 'classMethods',
event: 'events',
var: 'vars',
};

// The keys to not promote when promoting children.
export const UNPROMOTED_KEYS = ['textRaw', 'name', 'type', 'desc', 'miscs'];
77 changes: 77 additions & 0 deletions src/generators/legacy-json/index.mjs
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
'use strict';

import { writeFile } from 'node:fs/promises';
import { join } from 'node:path';
import { groupNodesByModule } from '../../utils/generators.mjs';
import { createSectionBuilder } from './utils/buildSection.mjs';

/**
* This generator is responsible for generating the legacy JSON files for the
* legacy API docs for retro-compatibility. It is to be replaced while we work
* on the new schema for this file.
*
* This is a top-level generator, intaking the raw AST tree of the api docs.
* It generates JSON files to the specified output directory given by the
* config.
*
* @typedef {Array<ApiDocMetadataEntry>} Input
*
* @type {import('../types.d.ts').GeneratorMetadata<Input, import('./types.d.ts').Section[]>}
*/
export default {
name: 'legacy-json',

version: '1.0.0',

description: 'Generates the legacy version of the JSON API docs.',

dependsOn: 'ast',

/**
* Generates a legacy JSON file.
*
* @param {Input} input
* @param {Partial<GeneratorOptions>} options
*/
async generate(input, { output }) {
const buildSection = createSectionBuilder();

// This array holds all the generated values for each module
const generatedValues = [];

const groupedModules = groupNodesByModule(input);

// Gets the first nodes of each module, which is considered the "head"
const headNodes = input.filter(node => node.heading.depth === 1);

/**
* @param {ApiDocMetadataEntry} head
* @returns {import('./types.d.ts').ModuleSection}
*/
const processModuleNodes = head => {
const nodes = groupedModules.get(head.api);

const section = buildSection(head, nodes);
generatedValues.push(section);

return section;
};

await Promise.all(
headNodes.map(async node => {
// Get the json for the node's section
const section = processModuleNodes(node);

// Write it to the output file
if (output) {
await writeFile(
join(output, `${node.api}.json`),
JSON.stringify(section)
);
}
})
);

return generatedValues;
},
};
Loading

0 comments on commit 8f40d5c

Please sign in to comment.