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

Use different escaping strategy for Liquid-style substitutions in YAML format front matter #804

Merged
merged 4 commits into from
Jul 12, 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
39 changes: 29 additions & 10 deletions src/models.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,31 @@ export type UserByLoginFunction = (login: string) => Promise<Contributor | null>
export type CollectionOfPluginsFunction = (output: string, options: PluginOptions) => string;
export type GetModifiedTimeByPathFunction = (filepath: string) => number | undefined;

/**
* VCS integration configuration object.
* Future VCS futures should be configured with this one, not with
* `VCSConnectorConfig`.
*/
interface VCSConfiguration {
/**
* Externally accessible base URI for a resource where a particular documentation
* source is hosted.
*
* This configuration parameter is used to directly control the Edit button behaviour
* in the Diplodoc documentation viewer(s).
*
* For example, if the following applies:
* - Repo with doc source is hosted on GitHub (say, https://github.com/foo-org/bar),
* - Within that particular repo, the directory that is being passed as an `--input`
* parameter to the CLI is located at `docs/`,
* - Whenever the Edit button is pressed, you wish to direct your readers to the
* respective document's source on `main` branch
*
* you should pass `https://github.com/foo-org/bar/tree/main/docs` as a value for this parameter.
*/
remoteBase: string;
}

interface YfmConfig {
varsPreset: VarsPreset;
ignore: string[];
Expand All @@ -41,6 +66,7 @@ interface YfmConfig {
ignoreStage: string;
singlePage: boolean;
removeHiddenTocItems: boolean;
vcs?: VCSConfiguration;
connector?: VCSConnectorConfig;
lang?: Lang;
langs?: Lang[];
Expand Down Expand Up @@ -199,20 +225,13 @@ export interface Contributors {
[email: string]: Contributor;
}

export interface FileData {
tmpInputFilePath: string;
inputFolderPathLength: number;
fileContent: string;
sourcePath?: string;
}

export interface MetaDataOptions {
fileData: FileData;
pathData: PathData;
isContributorsEnabled?: boolean;
vcsConnector?: VCSConnector;
addSystemMeta?: boolean;
addSourcePath?: boolean;
resources?: Resources;
shouldAlwaysAddVCSPath?: boolean;
}

export interface PluginOptions {
Expand All @@ -236,7 +255,7 @@ export interface Plugin {
export interface ResolveMd2MdOptions {
inputPath: string;
outputPath: string;
metadata?: MetaDataOptions;
metadata: MetaDataOptions;
}

export interface ResolverOptions {
Expand Down
21 changes: 12 additions & 9 deletions src/resolvers/md2md.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,29 +8,32 @@ import {ArgvService, PluginService} from '../services';
import {getVarsPerFile, logger} from '../utils';
import {PluginOptions, ResolveMd2MdOptions} from '../models';
import {PROCESSING_FINISHED} from '../constants';
import {getContentWithUpdatedMetadata} from '../services/metadata';
import {ChangelogItem} from '@diplodoc/transform/lib/plugins/changelog/types';
import {enrichWithFrontMatter} from '../services/metadata';

export async function resolveMd2Md(options: ResolveMd2MdOptions): Promise<void> {
const {inputPath, outputPath, metadata} = options;
const {inputPath, outputPath, metadata: metadataOptions} = options;
const {input, output, changelogs: changelogsSetting} = ArgvService.getConfig();
const resolvedInputPath = resolve(input, inputPath);

const vars = getVarsPerFile(inputPath);

const content = await getContentWithUpdatedMetadata(
readFileSync(resolvedInputPath, 'utf8'),
metadata,
vars.__system,
vars.__metadata,
);
const content = await enrichWithFrontMatter({
fileContent: readFileSync(resolvedInputPath, 'utf8'),
metadataOptions,
resolvedFrontMatterVars: {
systemVars: vars.__system as unknown,
metadataVars: vars.__metadata,
},
});

const {result, changelogs} = transformMd2Md(content, {
path: resolvedInputPath,
destPath: outputPath,
root: resolve(input),
destRoot: resolve(output),
collectOfPlugins: PluginService.getCollectOfPlugins(),
vars,
vars: vars,
log,
copyFile,
});
Expand Down
33 changes: 15 additions & 18 deletions src/services/authors.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
import {replaceDoubleToSingleQuotes} from '../utils';
import {Contributor} from '../models';
import {VCSConnector} from '../vcs-connector/connector-models';

async function updateAuthorMetadataStringByAuthorLogin(
authorLogin: string,
async function updateAuthorMetadataStringByAuthorData(
authorLogin: string | object,
vcsConnector?: VCSConnector,
): Promise<string> {
): Promise<Contributor | null> {
if (!vcsConnector) {
return '';
return null;
}

const user = await getAuthorDetails(vcsConnector, authorLogin);
Expand All @@ -15,52 +15,49 @@ async function updateAuthorMetadataStringByAuthorLogin(
return user;
}

return '';
return null;
}

async function updateAuthorMetadataStringByFilePath(
filePath: string,
vcsConnector?: VCSConnector,
): Promise<string> {
): Promise<Contributor | null> {
if (!vcsConnector) {
return '';
return null;
}

const user = vcsConnector.getExternalAuthorByPath(filePath);

if (user) {
const author = replaceDoubleToSingleQuotes(JSON.stringify(user));
return author;
return user;
}

return '';
return null;
}

async function getAuthorDetails(
vcsConnector: VCSConnector,
author: string | object,
): Promise<string | null> {
): Promise<Contributor | null> {
if (typeof author === 'object') {
// Avoiding problems when adding to html markup
return replaceDoubleToSingleQuotes(JSON.stringify(author));
return author as Contributor;
}

try {
JSON.parse(author);
return replaceDoubleToSingleQuotes(author);
return JSON.parse(author);
} catch {
const user = await vcsConnector.getUserByLogin(author);

if (user) {
return replaceDoubleToSingleQuotes(JSON.stringify(user));
return user;
}

return null;
}
}

export {
updateAuthorMetadataStringByAuthorLogin,
updateAuthorMetadataStringByAuthorData as updateAuthorMetadataStringByAuthorLogin,
updateAuthorMetadataStringByFilePath,
getAuthorDetails,
};
48 changes: 19 additions & 29 deletions src/services/contributors.ts
Original file line number Diff line number Diff line change
@@ -1,27 +1,22 @@
import {readFile} from 'fs/promises';
import {dirname, join} from 'path';

import {replaceDoubleToSingleQuotes} from '../utils';
import {REGEXP_INCLUDE_CONTENTS, REGEXP_INCLUDE_FILE_PATH} from '../constants';
import {Contributor, Contributors, FileData} from '../models';
import {Contributor, Contributors} from '../models';
import {FileContributors, VCSConnector} from '../vcs-connector/connector-models';

async function getFileContributorsMetadata(
fileData: FileData,
vcsConnector: VCSConnector,
): Promise<string> {
const contributors = await getFileContributorsString(fileData, vcsConnector);

return `contributors: ${contributors}`;
export interface ContributorsServiceFileData {
resolvedFilePath: string;
inputFolderPathLength: number;
fileContent: string;
}

async function getFileContributorsString(
fileData: FileData,
export async function getFileContributors(
fileData: ContributorsServiceFileData,
vcsConnector: VCSConnector,
): Promise<string> {
const {tmpInputFilePath, inputFolderPathLength} = fileData;
): Promise<Contributor[]> {
const {resolvedFilePath, inputFolderPathLength} = fileData;

const relativeFilePath = tmpInputFilePath.substring(inputFolderPathLength);
const relativeFilePath = resolvedFilePath.substring(inputFolderPathLength);
const fileContributors: FileContributors =
await vcsConnector.getContributorsByPath(relativeFilePath);
let nestedContributors: Contributors = {};
Expand All @@ -40,11 +35,11 @@ async function getFileContributorsString(
fileContributorsWithContributorsIncludedFiles,
).map(([, contributor]) => contributor);

return replaceDoubleToSingleQuotes(JSON.stringify(contributorsArray));
return contributorsArray;
}

async function getContributorsForNestedFiles(
fileData: FileData,
fileData: ContributorsServiceFileData,
vcsConnector: VCSConnector,
): Promise<Contributors> {
const {fileContent, inputFolderPathLength} = fileData;
Expand Down Expand Up @@ -77,10 +72,10 @@ async function getContributorsForNestedFiles(
throw err;
}

const newFileData: FileData = {
const newFileData: ContributorsServiceFileData = {
...fileData,
fileContent: contentIncludeFile,
tmpInputFilePath: relativeIncludeFilePath,
resolvedFilePath: relativeIncludeFilePath,
};

nestedContributors = await getContributorsForNestedFiles(newFileData, vcsConnector);
Expand All @@ -95,10 +90,9 @@ async function getContributorsForNestedFiles(
}

function getRelativeIncludeFilePaths(
fileData: Pick<FileData, 'tmpInputFilePath'>,
{resolvedFilePath: tmpInputFilePath}: ContributorsServiceFileData,
includeContents: string[],
): Set<string> {
const {tmpInputFilePath} = fileData;
const relativeIncludeFilePaths: Set<string> = new Set();

includeContents.forEach((includeContent: string) => {
Expand All @@ -118,10 +112,8 @@ function getRelativeIncludeFilePaths(
return relativeIncludeFilePaths;
}

async function getFileIncludes(
fileData: Pick<FileData, 'fileContent' | 'tmpInputFilePath' | 'inputFolderPathLength'>,
) {
const {fileContent, tmpInputFilePath, inputFolderPathLength} = fileData;
export async function getFileIncludes(fileData: ContributorsServiceFileData) {
const {fileContent, inputFolderPathLength} = fileData;

const results = new Set<string>();

Expand All @@ -130,7 +122,7 @@ async function getFileIncludes(
return [];
}
const relativeIncludeFilePaths: Set<string> = getRelativeIncludeFilePaths(
{tmpInputFilePath},
fileData,
includeContents,
);
for (const relativeIncludeFilePath of relativeIncludeFilePaths.values()) {
Expand All @@ -151,12 +143,10 @@ async function getFileIncludes(
const includedPaths = await getFileIncludes({
inputFolderPathLength,
fileContent: contentIncludeFile,
tmpInputFilePath: relativeIncludeFilePath,
resolvedFilePath: relativeIncludeFilePath,
});
includedPaths.forEach((path) => results.add(path));
}

return Array.from(results.values());
}

export {getFileContributorsMetadata, getFileContributorsString, getFileIncludes};
Loading
Loading