From edb6412e2a057d82558bc47ce7060782e8e5b6b5 Mon Sep 17 00:00:00 2001 From: v8tenko Date: Wed, 17 Jan 2024 18:04:51 +0300 Subject: [PATCH] feat: support metadata --- .eslintrc | 6 - .eslintrc.js | 11 + src/cmd/build/index.ts | 11 +- src/models.ts | 3 +- src/resolvers/md2html.ts | 8 +- src/resolvers/md2md.ts | 3 +- src/services/argv.ts | 5 + src/services/metadata.ts | 29 ++- src/utils/markup.ts | 58 +++-- .../__snapshots__/include-toc.test.ts.snap | 62 +---- .../load-custom-resources.spec.ts.snap | 27 +- tests/e2e/__snapshots__/metadata.spec.ts.snap | 245 ++++++++++++++++++ tests/e2e/metadata.spec.ts | 15 ++ .../md2html-with-resources/input/page.md | 6 +- .../md2md-with-resources/input/page.md | 6 +- .../single-page-with-resources/input/page.md | 6 +- .../metadata/md2html-with-metadata/input/.yfm | 5 + .../md2html-with-metadata/input/index.yaml | 9 + .../md2html-with-metadata/input/page.md | 7 + .../input/project/config.md | 7 + .../md2html-with-metadata/input/toc.yaml | 7 + .../metadata/md2md-with-metadata/input/.yfm | 5 + .../md2md-with-metadata/input/index.yaml | 9 + .../md2md-with-metadata/input/page.md | 7 + .../input/project/config.md | 7 + .../md2md-with-metadata/input/toc.yaml | 7 + tsconfig.json | 5 +- 27 files changed, 473 insertions(+), 103 deletions(-) delete mode 100644 .eslintrc create mode 100644 .eslintrc.js create mode 100644 tests/e2e/__snapshots__/metadata.spec.ts.snap create mode 100644 tests/e2e/metadata.spec.ts create mode 100644 tests/mocks/metadata/md2html-with-metadata/input/.yfm create mode 100644 tests/mocks/metadata/md2html-with-metadata/input/index.yaml create mode 100644 tests/mocks/metadata/md2html-with-metadata/input/page.md create mode 100644 tests/mocks/metadata/md2html-with-metadata/input/project/config.md create mode 100644 tests/mocks/metadata/md2html-with-metadata/input/toc.yaml create mode 100644 tests/mocks/metadata/md2md-with-metadata/input/.yfm create mode 100644 tests/mocks/metadata/md2md-with-metadata/input/index.yaml create mode 100644 tests/mocks/metadata/md2md-with-metadata/input/page.md create mode 100644 tests/mocks/metadata/md2md-with-metadata/input/project/config.md create mode 100644 tests/mocks/metadata/md2md-with-metadata/input/toc.yaml diff --git a/.eslintrc b/.eslintrc deleted file mode 100644 index c60b55323..000000000 --- a/.eslintrc +++ /dev/null @@ -1,6 +0,0 @@ -{ - "extends": ["@diplodoc/eslint-config"], - "env": { - "node": true - } -} diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..ccda1b82e --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,11 @@ +module.exports = { + "extends": ["@diplodoc/eslint-config"], + "root": true, + parserOptions: { + tsconfigRootDir: __dirname, + project: ['./tsconfig.json'], + }, + "env": { + "node": true + } +} diff --git a/src/cmd/build/index.ts b/src/cmd/build/index.ts index d34321cf0..48d466270 100644 --- a/src/cmd/build/index.ts +++ b/src/cmd/build/index.ts @@ -197,8 +197,13 @@ async function handler(args: Arguments) { addMapFile, allowCustomResources, resources, + metadata, } = ArgvService.getConfig(); + if (typeof metadata !== 'undefined' && !Array.isArray(metadata)) { + ArgvService.patch('metadata', [metadata]); + } + preparingTemporaryFolders(userOutputFolder); await processServiceFiles(); @@ -242,9 +247,9 @@ async function handler(args: Arguments) { // collect paths of all resources Object.keys(resources).forEach( (type) => - resources[type as keyof Resources]?.forEach((path: string) => - resourcePaths.push(path), - ), + resources[type as keyof Resources]?.forEach((path) => { + resourcePaths.push(path); + }), ); //copy resources diff --git a/src/models.ts b/src/models.ts index 2f78c192c..915089332 100644 --- a/src/models.ts +++ b/src/models.ts @@ -41,6 +41,7 @@ interface YfmConfig { buildDisabled: boolean; lintConfig: LintConfig; resources?: Resources; + metadata?: Record[]; yandexCloudTranslateFolderId: string; yandexCloudTranslateGlossaryPairs: YandexCloudTranslateGlossaryPair[]; } @@ -241,7 +242,7 @@ export interface PathData { } export type Resources = { - [key in ResourceType]?: string[]; + [type in ResourceType]?: string[]; }; export type YandexCloudTranslateGlossaryPair = { diff --git a/src/resolvers/md2html.ts b/src/resolvers/md2html.ts index ed75c2ad0..43c994198 100644 --- a/src/resolvers/md2html.ts +++ b/src/resolvers/md2html.ts @@ -43,7 +43,7 @@ export async function resolveMd2HTML(options: ResolverOptions): Promise { const {inputPath, outputPath, metadata} = options; - const {input, output} = ArgvService.getConfig(); + const {input, output, metadata: yfmMetadata} = ArgvService.getConfig(); const resolvedInputPath = resolve(input, inputPath); const vars = getVarsPerFile(inputPath); @@ -21,6 +21,7 @@ export async function resolveMd2Md(options: ResolveMd2MdOptions): Promise readFileSync(resolvedInputPath, 'utf8'), metadata, vars.__system, + yfmMetadata, ); const {result, changelogs} = transformMd2Md(content, { diff --git a/src/services/argv.ts b/src/services/argv.ts index 4941a6157..35dce0312 100644 --- a/src/services/argv.ts +++ b/src/services/argv.ts @@ -31,8 +31,13 @@ function set(argv: YfmArgv) { _argv = argv; } +function patch(field: Key, value: YfmArgv[Key]) { + _argv[field] = value; +} + export default { getConfig, init, set, + patch, }; diff --git a/src/services/metadata.ts b/src/services/metadata.ts index 544a7a44b..dde5fb472 100644 --- a/src/services/metadata.ts +++ b/src/services/metadata.ts @@ -1,4 +1,4 @@ -import {dump} from 'js-yaml'; +import {dump, load} from 'js-yaml'; import {VCSConnector} from '../vcs-connector/connector-models'; import {MetaDataOptions, Metadata, Resources} from '../models'; @@ -22,6 +22,7 @@ async function getContentWithUpdatedMetadata( fileContent: string, options?: MetaDataOptions, systemVars?: unknown, + yfmMetadata?: Record[], ): Promise { let result; @@ -32,7 +33,9 @@ async function getContentWithUpdatedMetadata( addSourcePath: options?.addSourcePath, resources: options?.resources, systemVars, + yfmMetadata, }); + result = await getContentWithUpdatedDynamicMetadata(result, options); return result; @@ -45,6 +48,7 @@ function getContentWithUpdatedStaticMetadata({ addSourcePath, resources, systemVars, + yfmMetadata = [], }: { fileContent: string; sourcePath?: string; @@ -52,10 +56,16 @@ function getContentWithUpdatedStaticMetadata({ addSourcePath?: boolean; resources?: Resources; systemVars?: unknown; + yfmMetadata?: Record[]; }): string { const newMetadatas: string[] = []; - if ((!addSystemMeta || !systemVars) && !addSourcePath && !resources) { + if ( + (!addSystemMeta || !systemVars) && + !addSourcePath && + !resources && + yfmMetadata.length === 0 + ) { return fileContent; } @@ -76,8 +86,21 @@ function getContentWithUpdatedStaticMetadata({ if (matches && matches.length > 0) { const [, fileMetadata, , fileMainContent] = matches; + const parsed = load(fileMetadata) as any; + + if (Array.isArray(parsed.metadata)) { + parsed.metadata = [...yfmMetadata, ...parsed.metadata]; + } else if (parsed.metadata) { + parsed.metadata = [...yfmMetadata, parsed.metadata]; + } + + const patchedMetada = dump(parsed); + + return `${getUpdatedMetadataString(newMetadatas, patchedMetada)}${fileMainContent}`; + } - return `${getUpdatedMetadataString(newMetadatas, fileMetadata)}${fileMainContent}`; + if (yfmMetadata.length) { + newMetadatas.push(dump({metadata: yfmMetadata})); } return `${getUpdatedMetadataString(newMetadatas)}${fileContent}`; diff --git a/src/utils/markup.ts b/src/utils/markup.ts index da1781b7b..abdaa76a6 100644 --- a/src/utils/markup.ts +++ b/src/utils/markup.ts @@ -1,8 +1,8 @@ import {join} from 'path'; import {platform} from 'process'; -import {CUSTOM_STYLE, Platforms, ResourceType} from '../constants'; -import {Resources, SinglePageResult} from '../models'; +import {CUSTOM_STYLE, Platforms} from '../constants'; +import {LeadingPage, Resources, SinglePageResult, TextItems} from '../models'; import {ArgvService, PluginService} from '../services'; import {preprocessPageHtmlForSinglePage} from './singlePage'; @@ -10,25 +10,31 @@ import {DocInnerProps, DocPageData, render} from '@diplodoc/client/ssr'; import manifest from '@diplodoc/client/manifest'; const dst = (bundlePath: string) => (target: string) => join(bundlePath, target); +export const сarriage = platform === Platforms.WINDOWS ? '\r\n' : '\n'; export interface TitleMeta { title?: string; } -export type Meta = TitleMeta & Resources; +type YfmMetadata = { + metadata: Record[]; +}; + +export type Meta = TitleMeta & Resources & YfmMetadata; export function generateStaticMarkup( props: DocInnerProps, pathToBundle: string, ): string { - const {title: metaTitle, style, script} = (props.data.meta as Meta) || {}; + const {style, script, metadata, ...restYamlConfigMeta} = (props.data.meta as Meta) || {}; const {title: tocTitle} = props.data.toc; const {title: pageTitle} = props.data; const title = getTitle({ - metaTitle, + metaTitle: props.data.meta.title, tocTitle: tocTitle as string, pageTitle, }); + const resources = getResources({style, script}); const {staticContent} = ArgvService.getConfig(); @@ -40,7 +46,7 @@ export function generateStaticMarkup( - ${getMetadata(props.data.meta as Record)} + ${getMetadata(metadata, restYamlConfigMeta)} ${title} + + + + +
+
+ + + + + + +`; + +exports[`Allow load custom resources md2html with metadata 3`] = ` + + + + + + + + + + Documentation + + + + + + +
+
+ + + + + + +`; + +exports[`Allow load custom resources md2html with metadata 4`] = ` + + + + + + + + + + Documentation + + + + + + +
+
+ + + + + + +`; + +exports[`Allow load custom resources md2md with metadata 1`] = `"[".yfm","index.yaml","page.md","project/config.md","toc.yaml"]"`; + +exports[`Allow load custom resources md2md with metadata 2`] = ` +"metadata: + - name: test-yfm + value: inline test + - name: yfm-config + value: config test +" +`; + +exports[`Allow load custom resources md2md with metadata 3`] = ` +"title: Documentation +description: '' +meta: + title: Documentation + noIndex: true +links: + - title: Getting started with Documentation + description: This guide will show you the basics of working with Documentation + href: page.md +" +`; + +exports[`Allow load custom resources md2md with metadata 4`] = ` +"--- +metadata: + - name: test-yfm + value: inline test + - name: yfm-config + value: config test + - name: yfm + value: builder in page +--- + +Lorem" +`; + +exports[`Allow load custom resources md2md with metadata 5`] = ` +"--- +metadata: + - name: test-yfm + value: inline test + - name: yfm-config + value: config test + - name: yfm + value: builder in config +--- + +Lorem" +`; + +exports[`Allow load custom resources md2md with metadata 6`] = ` +"title: Documentation +href: index.yaml +items: + - name: Documentation + href: page.md + - name: Config + href: project/config.md +base: . +" +`; diff --git a/tests/e2e/metadata.spec.ts b/tests/e2e/metadata.spec.ts new file mode 100644 index 000000000..b941ae27e --- /dev/null +++ b/tests/e2e/metadata.spec.ts @@ -0,0 +1,15 @@ +import {getTestPaths, runYfmDocs, compareDirectories} from '../utils'; + +const geretateMapTestTemplate = (testTitle: string, testRootPath: string, {md2md = true, md2html = true}) => { + test(testTitle, () => { + const {inputPath, outputPath} = getTestPaths(testRootPath); + runYfmDocs(inputPath, outputPath, {md2md, md2html}); + compareDirectories(outputPath); + }); +} + +describe('Allow load custom resources', () => { + geretateMapTestTemplate('md2md with metadata', 'mocks/metadata/md2md-with-metadata', {md2html: false}) + + geretateMapTestTemplate('md2html with metadata', 'mocks/metadata/md2html-with-metadata', {md2md: false}) +}); diff --git a/tests/mocks/load-custom-resources/md2html-with-resources/input/page.md b/tests/mocks/load-custom-resources/md2html-with-resources/input/page.md index 0f927d5c4..119b34481 100644 --- a/tests/mocks/load-custom-resources/md2html-with-resources/input/page.md +++ b/tests/mocks/load-custom-resources/md2html-with-resources/input/page.md @@ -1,5 +1,7 @@ --- -meta: some meta +metadata: + - name: yfm + value: builder --- -Lorem \ No newline at end of file +Lorem diff --git a/tests/mocks/load-custom-resources/md2md-with-resources/input/page.md b/tests/mocks/load-custom-resources/md2md-with-resources/input/page.md index 0f927d5c4..119b34481 100644 --- a/tests/mocks/load-custom-resources/md2md-with-resources/input/page.md +++ b/tests/mocks/load-custom-resources/md2md-with-resources/input/page.md @@ -1,5 +1,7 @@ --- -meta: some meta +metadata: + - name: yfm + value: builder --- -Lorem \ No newline at end of file +Lorem diff --git a/tests/mocks/load-custom-resources/single-page-with-resources/input/page.md b/tests/mocks/load-custom-resources/single-page-with-resources/input/page.md index 0f927d5c4..119b34481 100644 --- a/tests/mocks/load-custom-resources/single-page-with-resources/input/page.md +++ b/tests/mocks/load-custom-resources/single-page-with-resources/input/page.md @@ -1,5 +1,7 @@ --- -meta: some meta +metadata: + - name: yfm + value: builder --- -Lorem \ No newline at end of file +Lorem diff --git a/tests/mocks/metadata/md2html-with-metadata/input/.yfm b/tests/mocks/metadata/md2html-with-metadata/input/.yfm new file mode 100644 index 000000000..632e8cf45 --- /dev/null +++ b/tests/mocks/metadata/md2html-with-metadata/input/.yfm @@ -0,0 +1,5 @@ +metadata: + - name: test-yfm + value: inline test + - name: yfm-config + value: config test diff --git a/tests/mocks/metadata/md2html-with-metadata/input/index.yaml b/tests/mocks/metadata/md2html-with-metadata/input/index.yaml new file mode 100644 index 000000000..60f350c8d --- /dev/null +++ b/tests/mocks/metadata/md2html-with-metadata/input/index.yaml @@ -0,0 +1,9 @@ +title: Documentation +description: "" +meta: + title: Documentation + noIndex: true +links: + - title: Getting started with Documentation + description: This guide will show you the basics of working with Documentation + href: page.md diff --git a/tests/mocks/metadata/md2html-with-metadata/input/page.md b/tests/mocks/metadata/md2html-with-metadata/input/page.md new file mode 100644 index 000000000..d5a9a94c4 --- /dev/null +++ b/tests/mocks/metadata/md2html-with-metadata/input/page.md @@ -0,0 +1,7 @@ +--- +metadata: + - name: yfm + value: builder in page +--- + +Lorem \ No newline at end of file diff --git a/tests/mocks/metadata/md2html-with-metadata/input/project/config.md b/tests/mocks/metadata/md2html-with-metadata/input/project/config.md new file mode 100644 index 000000000..2e1519666 --- /dev/null +++ b/tests/mocks/metadata/md2html-with-metadata/input/project/config.md @@ -0,0 +1,7 @@ +--- +metadata: + - name: yfm + value: builder in config +--- + +Lorem \ No newline at end of file diff --git a/tests/mocks/metadata/md2html-with-metadata/input/toc.yaml b/tests/mocks/metadata/md2html-with-metadata/input/toc.yaml new file mode 100644 index 000000000..35f2b4c6c --- /dev/null +++ b/tests/mocks/metadata/md2html-with-metadata/input/toc.yaml @@ -0,0 +1,7 @@ +title: Documentation +href: index.yaml +items: + - name: Documentation + href: page.md + - name: Config + href: project/config.md \ No newline at end of file diff --git a/tests/mocks/metadata/md2md-with-metadata/input/.yfm b/tests/mocks/metadata/md2md-with-metadata/input/.yfm new file mode 100644 index 000000000..632e8cf45 --- /dev/null +++ b/tests/mocks/metadata/md2md-with-metadata/input/.yfm @@ -0,0 +1,5 @@ +metadata: + - name: test-yfm + value: inline test + - name: yfm-config + value: config test diff --git a/tests/mocks/metadata/md2md-with-metadata/input/index.yaml b/tests/mocks/metadata/md2md-with-metadata/input/index.yaml new file mode 100644 index 000000000..60f350c8d --- /dev/null +++ b/tests/mocks/metadata/md2md-with-metadata/input/index.yaml @@ -0,0 +1,9 @@ +title: Documentation +description: "" +meta: + title: Documentation + noIndex: true +links: + - title: Getting started with Documentation + description: This guide will show you the basics of working with Documentation + href: page.md diff --git a/tests/mocks/metadata/md2md-with-metadata/input/page.md b/tests/mocks/metadata/md2md-with-metadata/input/page.md new file mode 100644 index 000000000..d5a9a94c4 --- /dev/null +++ b/tests/mocks/metadata/md2md-with-metadata/input/page.md @@ -0,0 +1,7 @@ +--- +metadata: + - name: yfm + value: builder in page +--- + +Lorem \ No newline at end of file diff --git a/tests/mocks/metadata/md2md-with-metadata/input/project/config.md b/tests/mocks/metadata/md2md-with-metadata/input/project/config.md new file mode 100644 index 000000000..2e1519666 --- /dev/null +++ b/tests/mocks/metadata/md2md-with-metadata/input/project/config.md @@ -0,0 +1,7 @@ +--- +metadata: + - name: yfm + value: builder in config +--- + +Lorem \ No newline at end of file diff --git a/tests/mocks/metadata/md2md-with-metadata/input/toc.yaml b/tests/mocks/metadata/md2md-with-metadata/input/toc.yaml new file mode 100644 index 000000000..35f2b4c6c --- /dev/null +++ b/tests/mocks/metadata/md2md-with-metadata/input/toc.yaml @@ -0,0 +1,7 @@ +title: Documentation +href: index.yaml +items: + - name: Documentation + href: page.md + - name: Config + href: project/config.md \ No newline at end of file diff --git a/tsconfig.json b/tsconfig.json index 4572080e5..9f6569773 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -1,9 +1,10 @@ { "extends": "@diplodoc/tsconfig", "compilerOptions": { + "lib": ["ES2019"], "target": "es6", - "moduleResolution": "NodeNext", - "outDir": "build" + "outDir": "build", + "module": "CommonJS" }, "include": ["src"], "exclude": ["node_modules"],