Skip to content
This repository has been archived by the owner on Oct 9, 2024. It is now read-only.

Commit

Permalink
Fix documentation fragment discovery (#40)
Browse files Browse the repository at this point in the history
  • Loading branch information
tomaciazek authored Sep 28, 2021
1 parent 278b694 commit 1c7e58c
Show file tree
Hide file tree
Showing 3 changed files with 61 additions and 33 deletions.
2 changes: 1 addition & 1 deletion src/interfaces/module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ export interface IModuleMetadata {
namespace: string;
collection: string;
name: string;
rawDocumentation: Record<string, unknown>;
rawDocumentationFragments: Map<string, Record<string, unknown>>;
documentation?: IModuleDocumentation;
fragments?: IModuleMetadata[];
errors: YAMLError[];
Expand Down
4 changes: 3 additions & 1 deletion src/services/docsLibrary.ts
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ export class DocsLibrary {
}
if (!module.documentation) {
// translate raw documentation into a typed structure
module.documentation = processRawDocumentation(module.rawDocumentation);
module.documentation = processRawDocumentation(
module.rawDocumentationFragments
);
}
}
return [module, hitFqcn];
Expand Down
88 changes: 57 additions & 31 deletions src/utils/docsParser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -16,38 +16,54 @@ import {
IPluginTypes,
} from '../interfaces/pluginRouting';

const DOCUMENTATION = 'DOCUMENTATION';

export function processDocumentationFragments(
module: IModuleMetadata,
docFragments: Map<string, IModuleMetadata>
): void {
module.fragments = [];
const mainDocumentationFragment =
module.rawDocumentationFragments.get(DOCUMENTATION);
if (
hasOwnProperty(module.rawDocumentation, 'extends_documentation_fragment')
mainDocumentationFragment &&
hasOwnProperty(mainDocumentationFragment, 'extends_documentation_fragment')
) {
const docFragmentNames =
module.rawDocumentation.extends_documentation_fragment instanceof Array
? module.rawDocumentation.extends_documentation_fragment
: [module.rawDocumentation.extends_documentation_fragment];
const docFragmentNames: string[] =
mainDocumentationFragment.extends_documentation_fragment instanceof Array
? mainDocumentationFragment.extends_documentation_fragment
: [mainDocumentationFragment.extends_documentation_fragment];
const resultContents = {};
for (const docFragmentName of docFragmentNames) {
const fragmentNameArray = docFragmentName.split('.');
let fragmentPartName: string;
if (fragmentNameArray.length === 2 || fragmentNameArray.length === 4) {
fragmentPartName = fragmentNameArray.pop()?.toUpperCase() as string;
} else {
fragmentPartName = DOCUMENTATION;
}
const docFragmentCatalogueName = fragmentNameArray.join('.');
const docFragment =
docFragments.get(docFragmentName) ||
docFragments.get(`ansible.builtin.${docFragmentName}`);
if (docFragment) {
docFragments.get(docFragmentCatalogueName) ||
docFragments.get(`ansible.builtin.${docFragmentCatalogueName}`);
if (
docFragment &&
docFragment.rawDocumentationFragments.has(fragmentPartName)
) {
module.fragments.push(docFragment); // currently used only as indicator
_.mergeWith(
resultContents,
docFragment.rawDocumentation,
docFragment.rawDocumentationFragments.get(fragmentPartName),
docFragmentMergeCustomizer
);
}
}
_.mergeWith(
resultContents,
module.rawDocumentation,
mainDocumentationFragment,
docFragmentMergeCustomizer
);
module.rawDocumentation = resultContents;
module.rawDocumentationFragments.set(DOCUMENTATION, resultContents);
}
}

Expand All @@ -65,9 +81,11 @@ function docFragmentMergeCustomizer(
}

export function processRawDocumentation(
rawDoc: unknown
moduleDocParts: Map<string, Record<string, unknown>>
): IModuleDocumentation | undefined {
if (isObject(rawDoc) && typeof rawDoc.module === 'string') {
// currently processing only the main documentation
const rawDoc = moduleDocParts.get(DOCUMENTATION);
if (rawDoc && typeof rawDoc.module === 'string') {
const moduleDoc: IModuleDocumentation = {
module: rawDoc.module,
options: processRawOptions(rawDoc.options),
Expand Down Expand Up @@ -200,7 +218,7 @@ function parseRawDepracationOrTombstone(

export class LazyModuleDocumentation implements IModuleMetadata {
public static docsRegex =
/(?<pre>[ \t]*DOCUMENTATION\s*=\s*r?(?<quotes>'''|""")(?:\n---)?\n?)(?<doc>.*?)\k<quotes>/s;
/(?<pre>[ \t]*(?<name>[A-Z0-9_]+)\s*=\s*r?(?<quotes>'''|""")(?:\n---)?\n?)(?<doc>.*?)\k<quotes>/gs;

source: string;
sourceLineRange: [number, number] = [0, 0];
Expand All @@ -210,7 +228,7 @@ export class LazyModuleDocumentation implements IModuleMetadata {
name: string;
errors: YAMLError[] = [];

private _contents: Record<string, unknown> | undefined;
private _contents: Map<string, Record<string, unknown>> | undefined;

constructor(
source: string,
Expand All @@ -226,29 +244,37 @@ export class LazyModuleDocumentation implements IModuleMetadata {
this.name = name;
}

public get rawDocumentation(): Record<string, unknown> {
public get rawDocumentationFragments(): Map<string, Record<string, unknown>> {
if (!this._contents) {
this._contents = new Map<string, Record<string, unknown>>();
const contents = fs.readFileSync(this.source, { encoding: 'utf8' });
const m = LazyModuleDocumentation.docsRegex.exec(contents);
if (m && m.groups && m.groups.doc && m.groups.pre) {
// determine documentation start/end lines for definition provider
let startLine = contents.substr(0, m.index).match(/\n/g)?.length || 0;
startLine += m.groups.pre.match(/\n/g)?.length || 0;
const endLine = startLine + (m.groups.doc.match(/\n/g)?.length || 0);
this.sourceLineRange = [startLine, endLine];

const document = parseDocument(m.groups.doc);
// There's about 20 modules (out of ~3200) in Ansible 2.9 libs that contain YAML syntax errors
// Still, document.toJSON() works on them
this._contents = document.toJSON();
this.errors = document.errors;
let m;
while ((m = LazyModuleDocumentation.docsRegex.exec(contents)) !== null) {
if (m && m.groups && m.groups.name && m.groups.doc && m.groups.pre) {
if (m.groups.name === DOCUMENTATION) {
// determine documentation start/end lines for definition provider
let startLine =
contents.substr(0, m.index).match(/\n/g)?.length || 0;
startLine += m.groups.pre.match(/\n/g)?.length || 0;
const endLine =
startLine + (m.groups.doc.match(/\n/g)?.length || 0);
this.sourceLineRange = [startLine, endLine];
}

const document = parseDocument(m.groups.doc);
// There's about 20 modules (out of ~3200) in Ansible 2.9 libs that contain YAML syntax errors
// Still, document.toJSON() works on them
this._contents.set(m.groups.name, document.toJSON());
this.errors = document.errors;
}
}
this._contents = this._contents || {};
}
return this._contents;
}

public set rawDocumentation(value: Record<string, unknown>) {
public set rawDocumentationFragments(
value: Map<string, Record<string, unknown>>
) {
this._contents = value;
}
}

0 comments on commit 1c7e58c

Please sign in to comment.