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

fix: add support for sub toc files #764

Merged
merged 1 commit into from
May 17, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
8 changes: 4 additions & 4 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
"@diplodoc/mermaid-extension": "^1.2.1",
"@diplodoc/openapi-extension": "^2.1.0",
"@diplodoc/prettier-config": "^2.0.0",
"@diplodoc/transform": "^4.15.0",
"@diplodoc/transform": "^4.16.1",
"@diplodoc/tsconfig": "^1.0.2",
"@octokit/core": "4.2.4",
"@types/async": "^3.2.15",
Expand Down
2 changes: 2 additions & 0 deletions src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -96,12 +96,14 @@ export interface YfmToc extends Filter {
items: YfmToc[];
stage?: Stage;
base?: string;
deepBase?: number;
title?: TextItems;
include?: YfmTocInclude;
id?: string;
singlePage?: boolean;
hidden?: boolean;
label?: YfmTocLabel[] | YfmTocLabel;
root?: YfmToc;
}

export interface YfmTocInclude {
Expand Down
50 changes: 44 additions & 6 deletions src/resolvers/md2html.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import transform, {Output} from '@diplodoc/transform';
import liquid from '@diplodoc/transform/lib/liquid';
import log from '@diplodoc/transform/lib/log';
import {MarkdownItPluginCb} from '@diplodoc/transform/lib/plugins/typings';
import {getPublicPath} from '@diplodoc/transform/lib/utilsFS';
import {getPublicPath, isFileExists} from '@diplodoc/transform/lib/utilsFS';
import yaml from 'js-yaml';

import {Lang, PROCESSING_FINISHED} from '../constants';
Expand Down Expand Up @@ -79,7 +79,7 @@ const getFileProps = async (options: ResolverOptions) => {

const pathToDir: string = dirname(inputPath);
const toc: YfmToc | null = TocService.getForPath(inputPath) || null;
const tocBase: string = toc?.base ?? '';
const tocBase: string = toc?.root?.base || toc?.base || '';
const pathToFileDir: string =
pathToDir === tocBase ? '' : pathToDir.replace(`${tocBase}${sep}`, '');

Expand All @@ -92,14 +92,16 @@ const getFileProps = async (options: ResolverOptions) => {
const lang = tocLang || configLang || configLangs?.[0] || Lang.RU;
const langs = configLangs?.length ? configLangs : [lang];

const pathname = join(pathToFileDir, basename(outputPath));

const props = {
data: {
leading: inputPath.endsWith('.yaml'),
toc: transformToc(toc) || {},
...meta,
},
router: {
pathname: join(pathToFileDir, basename(outputPath)),
pathname,
},
lang,
langs,
Expand All @@ -119,6 +121,35 @@ export async function resolveMd2HTML(options: ResolverOptions): Promise<DocInner
return props;
}

function getHref(path: string, href: string) {
if (!href.includes('//')) {
const {input} = ArgvService.getConfig();
const root = resolve(input);
const assetRootPath = getAssetsRootPath(path) || '';

let filePath = resolve(input, dirname(path), href);

if (href.startsWith('/')) {
filePath = resolve(input, assetRootPath, href.replace(/^\/+/gi, ''));
}

href = getPublicPath(
{
root,
rootPublicPath: assetRootPath,
},
filePath,
);

if (isFileExists(filePath) || isFileExists(filePath + '.md')) {
href = href.replace(/\.md$/gi, '.html');
} else if (!/.+\.\w+$/gi.test(href)) {
href = href + '/';
}
}
return href;
}

function YamlFileTransformer(content: string, transformOptions: FileTransformOptions): Object {
let data: LeadingPage | null = null;

Expand Down Expand Up @@ -149,9 +180,16 @@ function YamlFileTransformer(content: string, transformOptions: FileTransformOpt
return result?.html;
});
} else {
const links = data?.links?.map((link) =>
link.href ? {...link, href: link.href.replace(/.md$/gmu, '.html')} : link,
);
const links = data?.links?.map((link) => {
if (link.href) {
const href = getHref(transformOptions.path, link.href);
return {
...link,
href,
};
}
return link;
});

if (links) {
data.links = links;
Expand Down
6 changes: 2 additions & 4 deletions src/services/metadata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ import {
import {isObject} from './utils';
import {сarriage} from '../utils';
import {REGEXP_AUTHOR, metadataBorder} from '../constants';
import {sep} from 'path';
import {TocService} from './index';

async function getContentWithUpdatedMetadata(
Expand Down Expand Up @@ -329,8 +328,7 @@ function getSystemVarsMetadataString(systemVars: object) {
function getAssetsPublicPath(filePath: string) {
const toc: YfmToc | null = TocService.getForPath(filePath) || null;

const basePath = toc?.base?.split(sep)?.filter((str) => str !== '.') || [];
const deepBase = basePath.length;
const deepBase = toc?.root?.deepBase || toc?.deepBase || 0;
const deepBasePath = deepBase > 0 ? Array(deepBase).fill('../').join('') : './';

/* Relative path from folder of .md file to root of user' output folder */
Expand All @@ -340,7 +338,7 @@ function getAssetsPublicPath(filePath: string) {
function getAssetsRootPath(filePath: string) {
const toc: YfmToc | null = TocService.getForPath(filePath) || null;

return toc?.base;
return toc?.root?.base || toc?.base;
}

export {
Expand Down
69 changes: 69 additions & 0 deletions src/services/tocs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,26 @@ let navigationPaths: TocServiceData['navigationPaths'] = [];
const includedTocPaths: TocServiceData['includedTocPaths'] = new Set();
const tocFileCopyMap = new Map<string, string>();

async function init(tocFilePaths: string[]) {
for (const path of tocFilePaths) {
logger.proc(path);

await add(path);
}

for (const path of tocFilePaths) {
logger.proc(path);

await addRoot(path);
}

for (const path of tocFilePaths) {
logger.proc(path);

await addNavigation(path);
}
}

async function add(path: string) {
const {
input: inputFolderPath,
Expand Down Expand Up @@ -83,6 +103,7 @@ async function add(path: string) {

/* Store path to toc file to handle relative paths in navigation */
parsedToc.base = pathToDir;
parsedToc.deepBase = pathToDir?.split(sep)?.filter((str) => str !== '.')?.length || 0;

if (outputFormat === 'md') {
/* Should copy resolved and filtered toc to output folder */
Expand All @@ -91,7 +112,37 @@ async function add(path: string) {
shell.mkdir('-p', dirname(outputPath));
writeFileSync(outputPath, outputToc);
}
}

// To collect root toc.yaml we need to move from root into deep
async function addRoot(path: string) {
const dirPath = dirname(path).split(sep);

const currentToc = getForPath(path);

if (!currentToc) {
return;
}

for (let index = 1; index < dirPath.length; index++) {
const dir = dirPath.slice(0, index);
const rootToc = getForPath(join(dir.join(sep), 'toc.yaml'));
if (rootToc) {
currentToc.root = rootToc;
return;
}
}
}

// To collect root toc.yaml we need to move from root into deep
async function addNavigation(path: string) {
const parsedToc = getForPath(path);

if (!parsedToc) {
return;
}

const pathToDir = dirname(path);
prepareNavigationPaths(parsedToc, pathToDir);
}

Expand Down Expand Up @@ -126,6 +177,21 @@ function getForPath(path: string): YfmToc | undefined {
return storage.get(path);
}

function getDeepForPath(path: string): {
deepBase: number;
deep: number;
} {
const toc: YfmToc | null = getForPath(path) || null;

const deepBase = toc?.root?.deepBase || toc?.deepBase || 0;
const deep = path.split(sep).length - 1 - deepBase;

return {
deepBase,
deep,
};
}

function getNavigationPaths(): string[] {
return [...navigationPaths];
}
Expand Down Expand Up @@ -421,8 +487,11 @@ function getAllTocs() {
}

export default {
init,
add,
process,
getForPath,
getDeepForPath,
getNavigationPaths,
getTocDir,
getIncludedTocPaths,
Expand Down
16 changes: 6 additions & 10 deletions src/steps/processPages.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import type {DocInnerProps} from '@diplodoc/client';
import {basename, dirname, extname, join, relative, resolve, sep} from 'path';
import {basename, dirname, extname, join, relative, resolve} from 'path';
import {existsSync, readFileSync, writeFileSync} from 'fs';
import log from '@diplodoc/transform/lib/log';
import {asyncify, mapLimit} from 'async';
Expand Down Expand Up @@ -171,13 +171,13 @@ async function saveSinglePages() {
langs,
};

const basePath = toc?.base?.split(sep)?.filter((str) => str !== '.') || [];
const deepBase = basePath.length;

// Save the full single page for viewing locally
const singlePageFn = join(tocDir, SINGLE_PAGE_FILENAME);
const singlePageDataFn = join(tocDir, SINGLE_PAGE_DATA_FILENAME);
const singlePageContent = generateStaticMarkup(pageData, deepBase);
const singlePageContent = generateStaticMarkup(
pageData,
toc?.root?.deepBase || toc?.deepBase || 0,
);

writeFileSync(singlePageFn, singlePageContent);
writeFileSync(singlePageDataFn, JSON.stringify(pageData));
Expand Down Expand Up @@ -358,11 +358,7 @@ async function processingFileToHtml(
metaDataOptions: MetaDataOptions,
): Promise<DocInnerProps> {
const {outputBundlePath, filename, fileExtension, outputPath, pathToFile} = path;
const toc: YfmToc | null = TocService.getForPath(pathToFile) || null;

const basePath = toc?.base?.split(sep)?.filter((str) => str !== '.') || [];
const deepBase = basePath.length;
const deep = pathToFile.split(sep).length - 1 - deepBase;
const {deepBase, deep} = TocService.getDeepForPath(pathToFile);

return resolveMd2HTML({
inputPath: pathToFile,
Expand Down
7 changes: 1 addition & 6 deletions src/steps/processServiceFiles.ts
Original file line number Diff line number Diff line change
Expand Up @@ -84,12 +84,7 @@ async function preparingTocFiles(
): Promise<void> {
try {
const tocFilePaths = getFilePathsByGlobals(['**/toc.yaml']);

for (const path of tocFilePaths) {
logger.proc(path);

await TocService.add(path);
}
await TocService.init(tocFilePaths);
} catch (error) {
log.error(`Preparing toc.yaml files failed. Error: ${error}`);
throw error;
Expand Down
13 changes: 9 additions & 4 deletions src/utils/toc.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import {basename, dirname, extname, format, join} from 'path';
import {basename, dirname, extname, format, join, relative} from 'path';

import {YfmToc} from '../models';
import {filterFiles} from '../services/utils';
Expand Down Expand Up @@ -39,14 +39,19 @@ export function transformToc(toc: YfmToc | null): YfmToc | null {
}

if (href && !isExternalHref(href)) {
const fileExtension: string = extname(href);
const filename: string = basename(href, fileExtension);
const relativeHref = join(
relative(toc.root?.base || toc.base || '', toc.base || ''),
href,
);

const fileExtension: string = extname(relativeHref);
const filename: string = basename(relativeHref, fileExtension);
const transformedFilename: string = format({
name: filename,
ext: '.html',
});

navigationItem.href = join(dirname(href), transformedFilename);
navigationItem.href = join(dirname(relativeHref), transformedFilename);
}
}

Expand Down
5 changes: 5 additions & 0 deletions tests/e2e/__snapshots__/include-toc.test.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ items:
- name: Article1
href: article1.md
base: product1
deepBase: 1
"
`;

Expand Down Expand Up @@ -107,6 +108,7 @@ items:
- name: Article1
href: overlay3/article1.md
base: product2
deepBase: 1
"
`;

Expand Down Expand Up @@ -140,6 +142,7 @@ exports[`Include toc Toc is included in link mode 5`] = `
- name: A1
href: folder1/folder2/a1.md
base: .
deepBase: 0
"
`;

Expand Down Expand Up @@ -254,6 +257,7 @@ exports[`Include toc Toc is included inline, not as a new section 12`] = `
- name: NameX
href: fileX.md
base: .
deepBase: 0
"
`;

Expand Down Expand Up @@ -284,5 +288,6 @@ items:
- name: A1
href: a1.md
base: .
deepBase: 0
"
`;
Loading
Loading