From 8291a172707d7a33cfda8c2bd0940b97869c41d3 Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Mon, 22 May 2023 18:24:00 +0500 Subject: [PATCH 1/8] changelogs --- package-lock.json | 86 +++++++++++--- package.json | 2 + src/transform/liquid/changelogs.ts | 47 ++++++++ src/transform/liquid/index.ts | 8 ++ src/transform/liquid/services/argv.ts | 1 + src/transform/plugins/changelog.ts | 157 ++++++++++++++++++++++++++ src/transform/typings.ts | 1 + test/changelog.test.ts | 37 ++++++ test/data/changelog.md | 15 +++ test/liquid/chaneglogs.test.ts | 22 ++++ 10 files changed, 360 insertions(+), 16 deletions(-) create mode 100644 src/transform/liquid/changelogs.ts create mode 100644 src/transform/plugins/changelog.ts create mode 100644 test/changelog.test.ts create mode 100644 test/data/changelog.md create mode 100644 test/liquid/chaneglogs.test.ts diff --git a/package-lock.json b/package-lock.json index d805ca89..c47150f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3344,6 +3344,15 @@ "resolve-from": "^5.0.0" }, "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, "find-up": { "version": "4.1.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", @@ -3354,6 +3363,16 @@ "path-exists": "^4.0.0" } }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, "locate-path": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", @@ -3915,6 +3934,12 @@ "pretty-format": "^28.0.0" } }, + "@types/js-yaml": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/@types/js-yaml/-/js-yaml-4.0.5.tgz", + "integrity": "sha512-FhpRzf927MNQdRZP0J5DLIdTXhjLYzeUTmLAu69mnVksLH9CJY3IuSeEgbKUki7GQZm0WqDkGzyxju2EZGD2wA==", + "dev": true + }, "@types/json-schema": { "version": "7.0.11", "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", @@ -6949,22 +6974,11 @@ "dev": true }, "js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", "requires": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" - }, - "dependencies": { - "argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "requires": { - "sprintf-js": "~1.0.2" - } - } + "argparse": "^2.0.1" } }, "jsbn": { @@ -7287,6 +7301,25 @@ "integrity": "sha1-11to8RVlnK9WjkrUPLRgpHEkjDk=", "requires": { "js-yaml": "^3.8.1" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } } }, "markdown-it-sup": { @@ -7303,6 +7336,27 @@ "chai": "^1.10.0", "js-yaml": "^3.13.1", "object-assign": "^4.1.1" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + } } }, "markdownlint": { @@ -8902,7 +8956,7 @@ "sprintf-js": { "version": "1.0.3", "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", - "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==" }, "sshpk": { "version": "1.16.1", diff --git a/package.json b/package.json index be87ca3b..50038942 100644 --- a/package.json +++ b/package.json @@ -34,6 +34,7 @@ "chalk": "4.1.2", "get-root-node-polyfill": "1.0.0", "github-slugger": "1.4.0", + "js-yaml": "^4.1.0", "lodash": "4.17.21", "markdown-it": "13.0.1", "markdown-it-attrs": "4.1.4", @@ -56,6 +57,7 @@ "@types/github-slugger": "1.3.0", "@types/highlight.js": "10.1.0", "@types/jest": "28.1.7", + "@types/js-yaml": "^4.0.5", "@types/lodash": "4.14.183", "@types/markdown-it": "12.2.3", "@types/markdown-it-attrs": "4.1.0", diff --git a/src/transform/liquid/changelogs.ts b/src/transform/liquid/changelogs.ts new file mode 100644 index 00000000..0ffeda27 --- /dev/null +++ b/src/transform/liquid/changelogs.ts @@ -0,0 +1,47 @@ +import {bold} from 'chalk'; +import {log} from '../log'; +import transform from '../index'; +import changelogPlugin from '../plugins/changelog'; +import imsize from '../plugins/imsize'; + +const BLOCK_START = '{% changelog %}'; +const BLOCK_END = '{% endChangelog %}\n'; + +function parseChangeLog(str: string) { + const { + result: {changelogs = []}, + } = transform(str, { + plugins: [changelogPlugin, imsize], + }); + return changelogs; +} + +const changelogs = (origStr: string, _builtVars: Record, path?: string) => { + let str = origStr; + let lastPos = 0; + const rawChangelogs = []; + + while (true) { + const pos = str.indexOf(BLOCK_START, lastPos); + if (pos === -1) { + break; + } + const endPos = str.indexOf(BLOCK_END, pos + BLOCK_START.length); + if (endPos === -1) { + log.error(`Changelog block must be closed${path ? ` in ${bold(path)}` : ''}`); + break; + } + + const changelog = str.slice(pos, endPos + BLOCK_END.length); + + rawChangelogs.push(changelog); + + str = str.slice(0, pos) + str.slice(endPos + BLOCK_END.length); + } + + const changelogs = parseChangeLog(rawChangelogs.join('\n\n')); + + return {output: str, changelogs}; +}; + +export = changelogs; diff --git a/src/transform/liquid/index.ts b/src/transform/liquid/index.ts index aec1bb22..b973c072 100644 --- a/src/transform/liquid/index.ts +++ b/src/transform/liquid/index.ts @@ -3,6 +3,7 @@ import {prepareSourceMap} from './sourceMap'; import applyCycles from './cycles'; import applyConditions from './conditions'; +import applyChangelogs from './changelogs'; import ArgvService, {ArgvSettings} from './services/argv'; import {Dictionary} from 'lodash'; @@ -81,6 +82,7 @@ function liquid< cycles = true, conditions = true, substitutions = true, + changelogs = false, conditionsInCode = false, keepNotVar = false, withSourceMap, @@ -90,6 +92,7 @@ function liquid< cycles, conditions, substitutions, + changelogs, conditionsInCode, keepNotVar, withSourceMap, @@ -120,6 +123,11 @@ function liquid< output = applySubstitutions(output, vars, path); } + if (changelogs) { + const result = applyChangelogs(output, vars, path); + output = result.output; + } + output = conditionsInCode ? output : repairCode(output); codes.length = 0; diff --git a/src/transform/liquid/services/argv.ts b/src/transform/liquid/services/argv.ts index a4de41a0..f8be1236 100644 --- a/src/transform/liquid/services/argv.ts +++ b/src/transform/liquid/services/argv.ts @@ -3,6 +3,7 @@ export type ArgvSettings = { conditionsInCode?: boolean; cycles?: boolean; substitutions?: boolean; + changelogs?: boolean; keepNotVar?: boolean; withSourceMap?: boolean; }; diff --git a/src/transform/plugins/changelog.ts b/src/transform/plugins/changelog.ts new file mode 100644 index 00000000..ea1273f2 --- /dev/null +++ b/src/transform/plugins/changelog.ts @@ -0,0 +1,157 @@ +import {MarkdownItPluginCb} from './typings'; +import Core from 'markdown-it/lib/parser_core'; +import Token from 'markdown-it/lib/token'; +import {bold} from 'chalk'; +import yaml from 'js-yaml'; +import StateCore from 'markdown-it/lib/rules_core/state_core'; + +interface Metadata { + date: string; +} + +const CHANGELOG_OPEN_RE = /^\{% changelog %}/; +const CHANGELOG_CLOSE_RE = /^\{% endChangelog %}/; + +function isOpenToken(tokens: Token[], i: number) { + return ( + tokens[i].type === 'paragraph_open' && + tokens[i + 1].type === 'inline' && + tokens[i + 2].type === 'paragraph_close' && + CHANGELOG_OPEN_RE.test(tokens[i + 1].content) + ); +} + +function isCloseToken(tokens: Token[], i: number) { + return ( + tokens[i].type === 'paragraph_open' && + tokens[i + 1].type === 'inline' && + tokens[i + 2].type === 'paragraph_close' && + CHANGELOG_CLOSE_RE.test(tokens[i + 1].content) + ); +} + +function isTitle(tokens: Token[], i = 0) { + return ( + tokens[i].type === 'heading_open' && + tokens[i + 1].type === 'inline' && + tokens[i + 2].type === 'heading_close' + ); +} + +function isImageParagraph(tokens: Token[], i = 0) { + return ( + tokens[i].type === 'paragraph_open' && + tokens[i + 1].type === 'inline' && + tokens[i + 2].type === 'paragraph_close' && + tokens[i + 1].children?.some((t) => t.type === 'image') + ); +} + +function parseBody(tokens: Token[], state: StateCore) { + const {md, env} = state; + + const metadataToken = tokens.shift(); + if (metadataToken?.type !== 'fence') { + throw new Error('Metadata tag not found'); + } + const rawMetadata = yaml.load(metadataToken.content) as Metadata; + const metadata = { + ...rawMetadata, + date: new Date(rawMetadata.date).toISOString(), + }; + + if (!isTitle(tokens)) { + throw new Error('Title tag not found'); + } + const title = tokens.splice(0, 3)[1].content; + + let image; + if (isImageParagraph(tokens)) { + const paragraphTokens = tokens.splice(0, 3); + const imageToken = paragraphTokens[1]?.children?.find((token) => token.type === 'image'); + if (imageToken) { + const width = Number(imageToken.attrGet('width')); + const height = Number(imageToken.attrGet('height')); + let ratio; + if (Number.isFinite(width) && Number.isFinite(height)) { + ratio = height / width; + } + let alt = imageToken.attrGet('title') || ''; + if (!alt && imageToken.children) { + alt = md.renderer.renderInlineAsText(imageToken.children, md.options, env); + } + image = { + src: imageToken.attrGet('src'), + alt, + ratio, + }; + } + } + + const description = md.renderer.render(tokens, md.options, env); + + return { + ...metadata, + title, + image, + description, + }; +} + +const changelog: MarkdownItPluginCb = function (md, {log, path}) { + const plugin: Core.RuleCore = (state) => { + const {tokens, env} = state; + const sections = []; + + for (let i = 0, len = tokens.length; i < len; i++) { + const isOpen = isOpenToken(tokens, i); + if (!isOpen) continue; + + const openAt = i; + let isCloseFound = false; + while (i < len) { + i++; + if (isCloseToken(tokens, i)) { + isCloseFound = true; + break; + } + } + + if (!isCloseFound) { + log.error(`Changelog close tag in not found: ${bold(path)}`); + break; + } + + const closeAt = i + 2; + const content = tokens.slice(openAt, closeAt + 1); + + // cut open + content.splice(0, 3); + // cut close + content.splice(-3); + + try { + sections.push(parseBody(content, state)); + } catch (err) { + log.error(`Changelog error: ${(err as Error).message} in ${bold(path)}`); + } + + tokens.splice(openAt, closeAt + 1 - openAt); + len = tokens.length; + } + + if (!env?.changelogs) { + env.changelogs = []; + } + + env.changelogs.push(...sections); + }; + + try { + md.core.ruler.before('curly_attributes', 'changelog', plugin); + } catch (e) { + md.core.ruler.push('changelog', plugin); + } +}; + +export = changelog; diff --git a/src/transform/typings.ts b/src/transform/typings.ts index 431657d7..7c06dced 100644 --- a/src/transform/typings.ts +++ b/src/transform/typings.ts @@ -58,4 +58,5 @@ export type EnvType = { headings: Heading[]; assets?: unknown[]; meta?: object; + changelogs?: unknown[]; } & Extras; diff --git a/test/changelog.test.ts b/test/changelog.test.ts new file mode 100644 index 00000000..07281a4f --- /dev/null +++ b/test/changelog.test.ts @@ -0,0 +1,37 @@ +import transform from '../src/transform'; +import path from 'path'; +import fs from 'fs'; +import changelogPlugin from "../src/transform/plugins/changelog"; +import imsize from "../src/transform/plugins/imsize"; + +describe('Changelog', () => { + test('Should cut changelogs and return changelogs', async () => { + expect.assertions(2); + + const data = await fs.promises.readFile(path.join(__dirname, 'data/changelog.md'), 'utf8'); + + const { + result: {html, changelogs: logs}, + } = transform(data, { + plugins: [changelogPlugin, imsize], + }); + + expect(html).toBe( + `

Some changelog

\n

After changelog

\n`, + ); + + expect(logs).toEqual([ + { + date: '2023-05-10T00:00:00.000Z', + storyId: 123321, + title: 'Change log title', + image: { + alt: 'My image', + ratio: 0.5625, + src: '../src/asd.png', + }, + description: '

Change log payload

\n', + }, + ]); + }); +}); diff --git a/test/data/changelog.md b/test/data/changelog.md new file mode 100644 index 00000000..4b207d94 --- /dev/null +++ b/test/data/changelog.md @@ -0,0 +1,15 @@ +# Some changelog + +{% changelog %} +``` +date: 2023-05-10 +storyId: 123321 +``` +# Change log title +![My image](../src/asd.png =16x9) + +Change log payload + +{% endChangelog %} + +After changelog diff --git a/test/liquid/chaneglogs.test.ts b/test/liquid/chaneglogs.test.ts new file mode 100644 index 00000000..e33d00e7 --- /dev/null +++ b/test/liquid/chaneglogs.test.ts @@ -0,0 +1,22 @@ +import changelogs from '../../src/transform/liquid/changelogs'; +import fs from 'fs'; +import path from 'path'; + +describe('Changelogs', () => { + test('Should cut changelogs and return changelogs', async () => { + expect.assertions(2); + + const data = await fs.promises.readFile( + path.join(__dirname, '../data/changelog.md'), + 'utf8', + ); + + const {output, changelogs: logs} = changelogs(data, {}); + expect(output).toBe(`# Some changelog + + +After changelog +`); + expect(logs.length).toBe(1); + }); +}); From 89eefa450244227ef6c04091e6bb120ed021e198 Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Mon, 22 May 2023 22:16:19 +0500 Subject: [PATCH 2/8] add write file --- src/transform/liquid/changelogs.ts | 37 +++++++++++++++++++----------- src/transform/plugins/changelog.ts | 16 ++++++------- src/transform/plugins/typings.ts | 12 ++++++++++ src/transform/typings.ts | 4 ++-- test/changelog.test.ts | 10 ++++---- test/liquid/chaneglogs.test.ts | 2 +- 6 files changed, 51 insertions(+), 30 deletions(-) diff --git a/src/transform/liquid/changelogs.ts b/src/transform/liquid/changelogs.ts index 0ffeda27..5deca1f4 100644 --- a/src/transform/liquid/changelogs.ts +++ b/src/transform/liquid/changelogs.ts @@ -1,47 +1,58 @@ import {bold} from 'chalk'; import {log} from '../log'; -import transform from '../index'; import changelogPlugin from '../plugins/changelog'; import imsize from '../plugins/imsize'; +import initMarkdownit from '../md'; +import path from 'path'; +import fs from 'fs'; const BLOCK_START = '{% changelog %}'; const BLOCK_END = '{% endChangelog %}\n'; -function parseChangeLog(str: string) { - const { - result: {changelogs = []}, - } = transform(str, { +function parseChangelogs(str: string) { + const {parse, compile, env} = initMarkdownit({ plugins: [changelogPlugin, imsize], }); - return changelogs; + + compile(parse(str)); + + return env.changelog || []; } -const changelogs = (origStr: string, _builtVars: Record, path?: string) => { +const changelogs = (origStr: string, _builtVars: Record, filepath?: string) => { let str = origStr; let lastPos = 0; - const rawChangelogs = []; + const rawChanges = []; + // eslint-disable-next-line no-constant-condition while (true) { const pos = str.indexOf(BLOCK_START, lastPos); + lastPos = pos; if (pos === -1) { break; } const endPos = str.indexOf(BLOCK_END, pos + BLOCK_START.length); if (endPos === -1) { - log.error(`Changelog block must be closed${path ? ` in ${bold(path)}` : ''}`); + log.error(`Changelog block must be closed${filepath ? ` in ${bold(filepath)}` : ''}`); break; } - const changelog = str.slice(pos, endPos + BLOCK_END.length); + const change = str.slice(pos, endPos + BLOCK_END.length); - rawChangelogs.push(changelog); + rawChanges.push(change); str = str.slice(0, pos) + str.slice(endPos + BLOCK_END.length); } - const changelogs = parseChangeLog(rawChangelogs.join('\n\n')); + const changes = parseChangelogs(rawChanges.join('\n\n')); + + changes.forEach((change) => { + if (!filepath) return; + const target = path.join(path.dirname(filepath), `change-${change.date}.json`); + fs.writeFileSync(target, JSON.stringify(change)); + }); - return {output: str, changelogs}; + return {output: str, changes}; }; export = changelogs; diff --git a/src/transform/plugins/changelog.ts b/src/transform/plugins/changelog.ts index ea1273f2..d454513f 100644 --- a/src/transform/plugins/changelog.ts +++ b/src/transform/plugins/changelog.ts @@ -101,7 +101,6 @@ function parseBody(tokens: Token[], state: StateCore) { const changelog: MarkdownItPluginCb = function (md, {log, path}) { const plugin: Core.RuleCore = (state) => { const {tokens, env} = state; - const sections = []; for (let i = 0, len = tokens.length; i < len; i++) { const isOpen = isOpenToken(tokens, i); @@ -131,20 +130,21 @@ const changelog: MarkdownItPluginCb = function (md, {log, path}) { content.splice(-3); try { - sections.push(parseBody(content, state)); + const change = parseBody(content, state); + + if (!env?.changelog) { + env.changelog = []; + } + + env.changelog.push(change); } catch (err) { log.error(`Changelog error: ${(err as Error).message} in ${bold(path)}`); + continue; } tokens.splice(openAt, closeAt + 1 - openAt); len = tokens.length; } - - if (!env?.changelogs) { - env.changelogs = []; - } - - env.changelogs.push(...sections); }; try { diff --git a/src/transform/plugins/typings.ts b/src/transform/plugins/typings.ts index 3a22af81..e98e1415 100644 --- a/src/transform/plugins/typings.ts +++ b/src/transform/plugins/typings.ts @@ -12,3 +12,15 @@ export interface MarkdownItPluginOpts { export type MarkdownItPluginCb = { (md: MarkdownIt, opts: T & MarkdownItPluginOpts): void; }; + +export interface ChangeLogItem { + title: string; + image: { + src: string; + alt: string; + ratio?: string; + }; + description: string; + date: string; + [x: string]: unknown; +} diff --git a/src/transform/typings.ts b/src/transform/typings.ts index 7c06dced..c27d2b40 100644 --- a/src/transform/typings.ts +++ b/src/transform/typings.ts @@ -2,7 +2,7 @@ import {LanguageFn} from 'highlight.js'; import DefaultMarkdownIt from 'markdown-it'; import DefaultStateCore from 'markdown-it/lib/rules_core/state_core'; import {SanitizeOptions} from './sanitize'; -import {MarkdownItPluginCb} from './plugins/typings'; +import {ChangeLogItem, MarkdownItPluginCb} from './plugins/typings'; import {LogLevels} from './log'; export interface MarkdownIt extends DefaultMarkdownIt { @@ -58,5 +58,5 @@ export type EnvType = { headings: Heading[]; assets?: unknown[]; meta?: object; - changelogs?: unknown[]; + changelog?: ChangeLogItem[]; } & Extras; diff --git a/test/changelog.test.ts b/test/changelog.test.ts index 07281a4f..8c5cb30c 100644 --- a/test/changelog.test.ts +++ b/test/changelog.test.ts @@ -1,8 +1,8 @@ import transform from '../src/transform'; import path from 'path'; import fs from 'fs'; -import changelogPlugin from "../src/transform/plugins/changelog"; -import imsize from "../src/transform/plugins/imsize"; +import changelogPlugin from '../src/transform/plugins/changelog'; +import imsize from '../src/transform/plugins/imsize'; describe('Changelog', () => { test('Should cut changelogs and return changelogs', async () => { @@ -11,14 +11,12 @@ describe('Changelog', () => { const data = await fs.promises.readFile(path.join(__dirname, 'data/changelog.md'), 'utf8'); const { - result: {html, changelogs: logs}, + result: {html, changelog: logs}, } = transform(data, { plugins: [changelogPlugin, imsize], }); - expect(html).toBe( - `

Some changelog

\n

After changelog

\n`, - ); + expect(html).toBe(`

Some changelog

\n

After changelog

\n`); expect(logs).toEqual([ { diff --git a/test/liquid/chaneglogs.test.ts b/test/liquid/chaneglogs.test.ts index e33d00e7..713ecd59 100644 --- a/test/liquid/chaneglogs.test.ts +++ b/test/liquid/chaneglogs.test.ts @@ -11,7 +11,7 @@ describe('Changelogs', () => { 'utf8', ); - const {output, changelogs: logs} = changelogs(data, {}); + const {output, changes: logs} = changelogs(data, {}); expect(output).toBe(`# Some changelog From deb1d2049420613da4e0b31d5376f4af0d4c4007 Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Mon, 22 May 2023 23:58:31 +0500 Subject: [PATCH 3/8] add enableChangelogs --- src/transform/liquid/changelogs.ts | 1 + src/transform/plugins.ts | 2 ++ src/transform/plugins/changelog.ts | 37 ++++++++++++++++++------------ src/transform/typings.ts | 1 + test/changelog.test.ts | 20 +++++++++++++++- 5 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/transform/liquid/changelogs.ts b/src/transform/liquid/changelogs.ts index 5deca1f4..f25226ff 100644 --- a/src/transform/liquid/changelogs.ts +++ b/src/transform/liquid/changelogs.ts @@ -12,6 +12,7 @@ const BLOCK_END = '{% endChangelog %}\n'; function parseChangelogs(str: string) { const {parse, compile, env} = initMarkdownit({ plugins: [changelogPlugin, imsize], + enableChangelogs: true, }); compile(parse(str)); diff --git a/src/transform/plugins.ts b/src/transform/plugins.ts index 116bbab7..ef62a380 100644 --- a/src/transform/plugins.ts +++ b/src/transform/plugins.ts @@ -14,6 +14,7 @@ import yfmTable from './plugins/table'; import file from './plugins/file'; import imsize from './plugins/imsize'; import term from './plugins/term'; +import changelog from './plugins/changelog'; const defaultPlugins = [ meta, @@ -30,6 +31,7 @@ const defaultPlugins = [ file, imsize, term, + changelog, ] as MarkdownItPluginCb[]; export = defaultPlugins; diff --git a/src/transform/plugins/changelog.ts b/src/transform/plugins/changelog.ts index d454513f..6e2990b3 100644 --- a/src/transform/plugins/changelog.ts +++ b/src/transform/plugins/changelog.ts @@ -9,6 +9,10 @@ interface Metadata { date: string; } +interface Options { + enableChangelogs?: boolean; +} + const CHANGELOG_OPEN_RE = /^\{% changelog %}/; const CHANGELOG_CLOSE_RE = /^\{% endChangelog %}/; @@ -98,7 +102,7 @@ function parseBody(tokens: Token[], state: StateCore) { }; } -const changelog: MarkdownItPluginCb = function (md, {log, path}) { +const changelog: MarkdownItPluginCb = function (md, {enableChangelogs, log, path}) { const plugin: Core.RuleCore = (state) => { const {tokens, env} = state; @@ -122,24 +126,27 @@ const changelog: MarkdownItPluginCb = function (md, {log, path}) { } const closeAt = i + 2; - const content = tokens.slice(openAt, closeAt + 1); - // cut open - content.splice(0, 3); - // cut close - content.splice(-3); + if (enableChangelogs) { + const content = tokens.slice(openAt, closeAt + 1); - try { - const change = parseBody(content, state); + // cut open + content.splice(0, 3); + // cut close + content.splice(-3); - if (!env?.changelog) { - env.changelog = []; - } + try { + const change = parseBody(content, state); - env.changelog.push(change); - } catch (err) { - log.error(`Changelog error: ${(err as Error).message} in ${bold(path)}`); - continue; + if (!env?.changelog) { + env.changelog = []; + } + + env.changelog.push(change); + } catch (err) { + log.error(`Changelog error: ${(err as Error).message} in ${bold(path)}`); + continue; + } } tokens.splice(openAt, closeAt + 1 - openAt); diff --git a/src/transform/typings.ts b/src/transform/typings.ts index c27d2b40..f80d9be6 100644 --- a/src/transform/typings.ts +++ b/src/transform/typings.ts @@ -43,6 +43,7 @@ export interface OptionsType { plugins?: MarkdownItPluginCb[]; highlightLangs?: HighlightLangMap; root?: string; + enableChangelogs?: boolean; [x: string]: unknown; } diff --git a/test/changelog.test.ts b/test/changelog.test.ts index 8c5cb30c..932bcd7e 100644 --- a/test/changelog.test.ts +++ b/test/changelog.test.ts @@ -5,7 +5,7 @@ import changelogPlugin from '../src/transform/plugins/changelog'; import imsize from '../src/transform/plugins/imsize'; describe('Changelog', () => { - test('Should cut changelogs and return changelogs', async () => { + test('Should cut changelog', async () => { expect.assertions(2); const data = await fs.promises.readFile(path.join(__dirname, 'data/changelog.md'), 'utf8'); @@ -14,6 +14,24 @@ describe('Changelog', () => { result: {html, changelog: logs}, } = transform(data, { plugins: [changelogPlugin, imsize], + enableChangelogs: false, + }); + + expect(html).toBe(`

Some changelog

\n

After changelog

\n`); + + expect(logs).toBe(undefined); + }); + + test('Should cut changelog and write it in env', async () => { + expect.assertions(2); + + const data = await fs.promises.readFile(path.join(__dirname, 'data/changelog.md'), 'utf8'); + + const { + result: {html, changelog: logs}, + } = transform(data, { + plugins: [changelogPlugin, imsize], + enableChangelogs: true, }); expect(html).toBe(`

Some changelog

\n

After changelog

\n`); From 73b27d58cfaf2d5f4aff7269a705e98a257244e9 Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Tue, 23 May 2023 12:17:15 +0500 Subject: [PATCH 4/8] withChangelogs --- src/transform/liquid/changelogs.ts | 16 ++++++-------- src/transform/liquid/index.ts | 31 ++++++++++++++++++--------- src/transform/liquid/services/argv.ts | 2 +- 3 files changed, 28 insertions(+), 21 deletions(-) diff --git a/src/transform/liquid/changelogs.ts b/src/transform/liquid/changelogs.ts index f25226ff..8edad904 100644 --- a/src/transform/liquid/changelogs.ts +++ b/src/transform/liquid/changelogs.ts @@ -3,8 +3,7 @@ import {log} from '../log'; import changelogPlugin from '../plugins/changelog'; import imsize from '../plugins/imsize'; import initMarkdownit from '../md'; -import path from 'path'; -import fs from 'fs'; +import {ChangeLogItem} from '../plugins/typings'; const BLOCK_START = '{% changelog %}'; const BLOCK_END = '{% endChangelog %}\n'; @@ -45,15 +44,12 @@ const changelogs = (origStr: string, _builtVars: Record, filepa str = str.slice(0, pos) + str.slice(endPos + BLOCK_END.length); } - const changes = parseChangelogs(rawChanges.join('\n\n')); - - changes.forEach((change) => { - if (!filepath) return; - const target = path.join(path.dirname(filepath), `change-${change.date}.json`); - fs.writeFileSync(target, JSON.stringify(change)); - }); + let changes: ChangeLogItem[] = []; + if (rawChanges.length) { + changes = parseChangelogs(rawChanges.join('\n\n')); + } - return {output: str, changes}; + return {output: str, changelogs: changes}; }; export = changelogs; diff --git a/src/transform/liquid/index.ts b/src/transform/liquid/index.ts index b973c072..40b3ef76 100644 --- a/src/transform/liquid/index.ts +++ b/src/transform/liquid/index.ts @@ -7,6 +7,7 @@ import applyChangelogs from './changelogs'; import ArgvService, {ArgvSettings} from './services/argv'; import {Dictionary} from 'lodash'; +import {ChangeLogItem} from '../plugins/typings'; const codes: string[] = []; @@ -70,19 +71,26 @@ function repairCode(str: string) { } function liquid< + D extends boolean = false, B extends boolean = false, - C = B extends false ? string : {output: string; sourceMap: Dictionary}, + C = B | D extends false + ? string + : { + output: string; + sourceMap: B extends false ? undefined : Dictionary; + changelogs: D extends false ? undefined : ChangeLogItem[]; + }, >( originInput: string, vars: Record, path?: string, - settings?: ArgvSettings & {withSourceMap?: B}, + settings?: ArgvSettings & {withSourceMap?: B; withChangelogs?: D}, ): C { const { cycles = true, conditions = true, substitutions = true, - changelogs = false, + withChangelogs = false, conditionsInCode = false, keepNotVar = false, withSourceMap, @@ -92,7 +100,7 @@ function liquid< cycles, conditions, substitutions, - changelogs, + withChangelogs, conditionsInCode, keepNotVar, withSourceMap, @@ -123,18 +131,21 @@ function liquid< output = applySubstitutions(output, vars, path); } - if (changelogs) { + output = conditionsInCode ? output : repairCode(output); + codes.length = 0; + + let changelogs; + if (withChangelogs) { const result = applyChangelogs(output, vars, path); output = result.output; + changelogs = result.changelogs; } - output = conditionsInCode ? output : repairCode(output); - codes.length = 0; - - if (withSourceMap) { + if (withSourceMap || withChangelogs) { return { output, - sourceMap: prepareSourceMap(sourceMap), + sourceMap: withSourceMap ? prepareSourceMap(sourceMap) : undefined, + changelogs: withChangelogs ? changelogs : undefined, } as unknown as C; } diff --git a/src/transform/liquid/services/argv.ts b/src/transform/liquid/services/argv.ts index f8be1236..78664cfa 100644 --- a/src/transform/liquid/services/argv.ts +++ b/src/transform/liquid/services/argv.ts @@ -3,7 +3,7 @@ export type ArgvSettings = { conditionsInCode?: boolean; cycles?: boolean; substitutions?: boolean; - changelogs?: boolean; + withChangelogs?: boolean; keepNotVar?: boolean; withSourceMap?: boolean; }; From ae5401c2b95cb5d2d69f5911730ba50d26cfb29c Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Tue, 23 May 2023 12:21:59 +0500 Subject: [PATCH 5/8] extractChangelogs --- src/transform/liquid/changelogs.ts | 2 +- src/transform/plugins.ts | 2 -- src/transform/plugins/changelog.ts | 8 ++++---- src/transform/typings.ts | 2 +- 4 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/transform/liquid/changelogs.ts b/src/transform/liquid/changelogs.ts index 8edad904..37e8f54f 100644 --- a/src/transform/liquid/changelogs.ts +++ b/src/transform/liquid/changelogs.ts @@ -11,7 +11,7 @@ const BLOCK_END = '{% endChangelog %}\n'; function parseChangelogs(str: string) { const {parse, compile, env} = initMarkdownit({ plugins: [changelogPlugin, imsize], - enableChangelogs: true, + extractChangelogs: true, }); compile(parse(str)); diff --git a/src/transform/plugins.ts b/src/transform/plugins.ts index ef62a380..116bbab7 100644 --- a/src/transform/plugins.ts +++ b/src/transform/plugins.ts @@ -14,7 +14,6 @@ import yfmTable from './plugins/table'; import file from './plugins/file'; import imsize from './plugins/imsize'; import term from './plugins/term'; -import changelog from './plugins/changelog'; const defaultPlugins = [ meta, @@ -31,7 +30,6 @@ const defaultPlugins = [ file, imsize, term, - changelog, ] as MarkdownItPluginCb[]; export = defaultPlugins; diff --git a/src/transform/plugins/changelog.ts b/src/transform/plugins/changelog.ts index 6e2990b3..6cd816b6 100644 --- a/src/transform/plugins/changelog.ts +++ b/src/transform/plugins/changelog.ts @@ -10,7 +10,7 @@ interface Metadata { } interface Options { - enableChangelogs?: boolean; + extractChangelogs?: boolean; } const CHANGELOG_OPEN_RE = /^\{% changelog %}/; @@ -102,7 +102,7 @@ function parseBody(tokens: Token[], state: StateCore) { }; } -const changelog: MarkdownItPluginCb = function (md, {enableChangelogs, log, path}) { +const changelog: MarkdownItPluginCb = function (md, {extractChangelogs, log, path}) { const plugin: Core.RuleCore = (state) => { const {tokens, env} = state; @@ -127,7 +127,7 @@ const changelog: MarkdownItPluginCb = function (md, {enableChangelogs, const closeAt = i + 2; - if (enableChangelogs) { + if (env && extractChangelogs) { const content = tokens.slice(openAt, closeAt + 1); // cut open @@ -138,7 +138,7 @@ const changelog: MarkdownItPluginCb = function (md, {enableChangelogs, try { const change = parseBody(content, state); - if (!env?.changelog) { + if (!env.changelog) { env.changelog = []; } diff --git a/src/transform/typings.ts b/src/transform/typings.ts index f80d9be6..bb74a07b 100644 --- a/src/transform/typings.ts +++ b/src/transform/typings.ts @@ -43,7 +43,7 @@ export interface OptionsType { plugins?: MarkdownItPluginCb[]; highlightLangs?: HighlightLangMap; root?: string; - enableChangelogs?: boolean; + extractChangelogs?: boolean; [x: string]: unknown; } From 9f0ad0a6dad5388b7653af33b2c09967cfb3fd47 Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Tue, 23 May 2023 12:57:38 +0500 Subject: [PATCH 6/8] fix --- src/transform/liquid/changelogs.ts | 7 ++++--- src/transform/plugins/changelog.ts | 9 +++++---- src/transform/typings.ts | 2 +- test/changelog.test.ts | 14 +++++++------- test/data/changelog.md | 25 +++++++++++++++++++++++++ test/liquid/chaneglogs.test.ts | 7 +++++-- 6 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/transform/liquid/changelogs.ts b/src/transform/liquid/changelogs.ts index 37e8f54f..37ccd94a 100644 --- a/src/transform/liquid/changelogs.ts +++ b/src/transform/liquid/changelogs.ts @@ -8,15 +8,16 @@ import {ChangeLogItem} from '../plugins/typings'; const BLOCK_START = '{% changelog %}'; const BLOCK_END = '{% endChangelog %}\n'; -function parseChangelogs(str: string) { +function parseChangelogs(str: string, path?: string) { const {parse, compile, env} = initMarkdownit({ plugins: [changelogPlugin, imsize], extractChangelogs: true, + path, }); compile(parse(str)); - return env.changelog || []; + return env.changelogs || []; } const changelogs = (origStr: string, _builtVars: Record, filepath?: string) => { @@ -46,7 +47,7 @@ const changelogs = (origStr: string, _builtVars: Record, filepa let changes: ChangeLogItem[] = []; if (rawChanges.length) { - changes = parseChangelogs(rawChanges.join('\n\n')); + changes = parseChangelogs(rawChanges.join('\n\n'), filepath); } return {output: str, changelogs: changes}; diff --git a/src/transform/plugins/changelog.ts b/src/transform/plugins/changelog.ts index 6cd816b6..97f66309 100644 --- a/src/transform/plugins/changelog.ts +++ b/src/transform/plugins/changelog.ts @@ -27,7 +27,7 @@ function isOpenToken(tokens: Token[], i: number) { function isCloseToken(tokens: Token[], i: number) { return ( - tokens[i].type === 'paragraph_open' && + tokens[i]?.type === 'paragraph_open' && tokens[i + 1].type === 'inline' && tokens[i + 2].type === 'paragraph_close' && CHANGELOG_CLOSE_RE.test(tokens[i + 1].content) @@ -138,11 +138,11 @@ const changelog: MarkdownItPluginCb = function (md, {extractChangelogs, try { const change = parseBody(content, state); - if (!env.changelog) { - env.changelog = []; + if (!env.changelogs) { + env.changelogs = []; } - env.changelog.push(change); + env.changelogs.push(change); } catch (err) { log.error(`Changelog error: ${(err as Error).message} in ${bold(path)}`); continue; @@ -151,6 +151,7 @@ const changelog: MarkdownItPluginCb = function (md, {extractChangelogs, tokens.splice(openAt, closeAt + 1 - openAt); len = tokens.length; + i = openAt - 1; } }; diff --git a/src/transform/typings.ts b/src/transform/typings.ts index bb74a07b..33658fa6 100644 --- a/src/transform/typings.ts +++ b/src/transform/typings.ts @@ -59,5 +59,5 @@ export type EnvType = { headings: Heading[]; assets?: unknown[]; meta?: object; - changelog?: ChangeLogItem[]; + changelogs?: ChangeLogItem[]; } & Extras; diff --git a/test/changelog.test.ts b/test/changelog.test.ts index 932bcd7e..7c9bfc34 100644 --- a/test/changelog.test.ts +++ b/test/changelog.test.ts @@ -11,7 +11,7 @@ describe('Changelog', () => { const data = await fs.promises.readFile(path.join(__dirname, 'data/changelog.md'), 'utf8'); const { - result: {html, changelog: logs}, + result: {html, changelogs: logs}, } = transform(data, { plugins: [changelogPlugin, imsize], enableChangelogs: false, @@ -28,16 +28,16 @@ describe('Changelog', () => { const data = await fs.promises.readFile(path.join(__dirname, 'data/changelog.md'), 'utf8'); const { - result: {html, changelog: logs}, + result: {html, changelogs: logs}, } = transform(data, { plugins: [changelogPlugin, imsize], - enableChangelogs: true, + extractChangelogs: true, }); expect(html).toBe(`

Some changelog

\n

After changelog

\n`); - expect(logs).toEqual([ - { + expect(logs).toEqual( + new Array(3).fill({ date: '2023-05-10T00:00:00.000Z', storyId: 123321, title: 'Change log title', @@ -47,7 +47,7 @@ describe('Changelog', () => { src: '../src/asd.png', }, description: '

Change log payload

\n', - }, - ]); + }), + ); }); }); diff --git a/test/data/changelog.md b/test/data/changelog.md index 4b207d94..c484713f 100644 --- a/test/data/changelog.md +++ b/test/data/changelog.md @@ -1,5 +1,30 @@ # Some changelog +{% changelog %} +``` +date: 2023-05-10 +storyId: 123321 +``` +# Change log title +![My image](../src/asd.png =16x9) + +Change log payload + +{% endChangelog %} + +{% changelog %} +``` +date: 2023-05-10 +storyId: 123321 +``` +# Change log title +![My image](../src/asd.png =16x9) + +Change log payload + +{% endChangelog %} + + {% changelog %} ``` date: 2023-05-10 diff --git a/test/liquid/chaneglogs.test.ts b/test/liquid/chaneglogs.test.ts index 713ecd59..faaabd4c 100644 --- a/test/liquid/chaneglogs.test.ts +++ b/test/liquid/chaneglogs.test.ts @@ -11,12 +11,15 @@ describe('Changelogs', () => { 'utf8', ); - const {output, changes: logs} = changelogs(data, {}); + const {output, changelogs: logs} = changelogs(data, {}); expect(output).toBe(`# Some changelog + + + After changelog `); - expect(logs.length).toBe(1); + expect(logs.length).toBe(3); }); }); From 75c4915120590c720c30ef9fdf6e8c389ddc8ffa Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Tue, 23 May 2023 15:43:23 +0500 Subject: [PATCH 7/8] use collect --- src/transform/liquid/changelogs.ts | 56 ----------------- src/transform/liquid/index.ts | 27 ++------- src/transform/liquid/services/argv.ts | 1 - src/transform/plugins/changelog/collect.ts | 60 +++++++++++++++++++ .../{changelog.ts => changelog/index.ts} | 2 +- src/transform/plugins/changelog/types.ts | 11 ++++ src/transform/plugins/typings.ts | 12 ---- src/transform/typings.ts | 5 +- test/changelog.test.ts | 27 +++++++++ test/liquid/chaneglogs.test.ts | 25 -------- 10 files changed, 106 insertions(+), 120 deletions(-) delete mode 100644 src/transform/liquid/changelogs.ts create mode 100644 src/transform/plugins/changelog/collect.ts rename src/transform/plugins/{changelog.ts => changelog/index.ts} (99%) create mode 100644 src/transform/plugins/changelog/types.ts delete mode 100644 test/liquid/chaneglogs.test.ts diff --git a/src/transform/liquid/changelogs.ts b/src/transform/liquid/changelogs.ts deleted file mode 100644 index 37ccd94a..00000000 --- a/src/transform/liquid/changelogs.ts +++ /dev/null @@ -1,56 +0,0 @@ -import {bold} from 'chalk'; -import {log} from '../log'; -import changelogPlugin from '../plugins/changelog'; -import imsize from '../plugins/imsize'; -import initMarkdownit from '../md'; -import {ChangeLogItem} from '../plugins/typings'; - -const BLOCK_START = '{% changelog %}'; -const BLOCK_END = '{% endChangelog %}\n'; - -function parseChangelogs(str: string, path?: string) { - const {parse, compile, env} = initMarkdownit({ - plugins: [changelogPlugin, imsize], - extractChangelogs: true, - path, - }); - - compile(parse(str)); - - return env.changelogs || []; -} - -const changelogs = (origStr: string, _builtVars: Record, filepath?: string) => { - let str = origStr; - let lastPos = 0; - const rawChanges = []; - - // eslint-disable-next-line no-constant-condition - while (true) { - const pos = str.indexOf(BLOCK_START, lastPos); - lastPos = pos; - if (pos === -1) { - break; - } - const endPos = str.indexOf(BLOCK_END, pos + BLOCK_START.length); - if (endPos === -1) { - log.error(`Changelog block must be closed${filepath ? ` in ${bold(filepath)}` : ''}`); - break; - } - - const change = str.slice(pos, endPos + BLOCK_END.length); - - rawChanges.push(change); - - str = str.slice(0, pos) + str.slice(endPos + BLOCK_END.length); - } - - let changes: ChangeLogItem[] = []; - if (rawChanges.length) { - changes = parseChangelogs(rawChanges.join('\n\n'), filepath); - } - - return {output: str, changelogs: changes}; -}; - -export = changelogs; diff --git a/src/transform/liquid/index.ts b/src/transform/liquid/index.ts index 40b3ef76..aec1bb22 100644 --- a/src/transform/liquid/index.ts +++ b/src/transform/liquid/index.ts @@ -3,11 +3,9 @@ import {prepareSourceMap} from './sourceMap'; import applyCycles from './cycles'; import applyConditions from './conditions'; -import applyChangelogs from './changelogs'; import ArgvService, {ArgvSettings} from './services/argv'; import {Dictionary} from 'lodash'; -import {ChangeLogItem} from '../plugins/typings'; const codes: string[] = []; @@ -71,26 +69,18 @@ function repairCode(str: string) { } function liquid< - D extends boolean = false, B extends boolean = false, - C = B | D extends false - ? string - : { - output: string; - sourceMap: B extends false ? undefined : Dictionary; - changelogs: D extends false ? undefined : ChangeLogItem[]; - }, + C = B extends false ? string : {output: string; sourceMap: Dictionary}, >( originInput: string, vars: Record, path?: string, - settings?: ArgvSettings & {withSourceMap?: B; withChangelogs?: D}, + settings?: ArgvSettings & {withSourceMap?: B}, ): C { const { cycles = true, conditions = true, substitutions = true, - withChangelogs = false, conditionsInCode = false, keepNotVar = false, withSourceMap, @@ -100,7 +90,6 @@ function liquid< cycles, conditions, substitutions, - withChangelogs, conditionsInCode, keepNotVar, withSourceMap, @@ -134,18 +123,10 @@ function liquid< output = conditionsInCode ? output : repairCode(output); codes.length = 0; - let changelogs; - if (withChangelogs) { - const result = applyChangelogs(output, vars, path); - output = result.output; - changelogs = result.changelogs; - } - - if (withSourceMap || withChangelogs) { + if (withSourceMap) { return { output, - sourceMap: withSourceMap ? prepareSourceMap(sourceMap) : undefined, - changelogs: withChangelogs ? changelogs : undefined, + sourceMap: prepareSourceMap(sourceMap), } as unknown as C; } diff --git a/src/transform/liquid/services/argv.ts b/src/transform/liquid/services/argv.ts index 78664cfa..a4de41a0 100644 --- a/src/transform/liquid/services/argv.ts +++ b/src/transform/liquid/services/argv.ts @@ -3,7 +3,6 @@ export type ArgvSettings = { conditionsInCode?: boolean; cycles?: boolean; substitutions?: boolean; - withChangelogs?: boolean; keepNotVar?: boolean; withSourceMap?: boolean; }; diff --git a/src/transform/plugins/changelog/collect.ts b/src/transform/plugins/changelog/collect.ts new file mode 100644 index 00000000..93cc5844 --- /dev/null +++ b/src/transform/plugins/changelog/collect.ts @@ -0,0 +1,60 @@ +import {bold} from 'chalk'; +import {ChangelogItem} from './types'; +import initMarkdownit from '../../md'; +import changelogPlugin from './index'; +import imsize from '../imsize'; +import {MarkdownItPluginOpts} from '../typings'; + +const BLOCK_START = '{% changelog %}'; +const BLOCK_END = '{% endChangelog %}\n'; + +function parseChangelogs(str: string, path?: string) { + const {parse, compile, env} = initMarkdownit({ + plugins: [changelogPlugin, imsize], + extractChangelogs: true, + path, + }); + + compile(parse(str)); + + return env.changelogs || []; +} + +type Options = Pick & { + changelogs?: ChangelogItem[]; + extractChangelogs?: boolean; +}; + +const collect = (input: string, {path: filepath, log, changelogs, extractChangelogs}: Options) => { + let result = input; + let lastPos = 0; + const rawChanges = []; + + // eslint-disable-next-line no-constant-condition + while (true) { + const pos = result.indexOf(BLOCK_START, lastPos); + lastPos = pos; + if (pos === -1) { + break; + } + const endPos = result.indexOf(BLOCK_END, pos + BLOCK_START.length); + if (endPos === -1) { + log.error(`Changelog block must be closed${filepath ? ` in ${bold(filepath)}` : ''}`); + break; + } + + const change = result.slice(pos, endPos + BLOCK_END.length); + + rawChanges.push(change); + + result = result.slice(0, pos) + result.slice(endPos + BLOCK_END.length); + } + + if (rawChanges.length && changelogs && extractChangelogs) { + changelogs.push(...parseChangelogs(rawChanges.join('\n\n'), filepath)); + } + + return result; +}; + +export = collect; diff --git a/src/transform/plugins/changelog.ts b/src/transform/plugins/changelog/index.ts similarity index 99% rename from src/transform/plugins/changelog.ts rename to src/transform/plugins/changelog/index.ts index 97f66309..f0e5febc 100644 --- a/src/transform/plugins/changelog.ts +++ b/src/transform/plugins/changelog/index.ts @@ -1,4 +1,4 @@ -import {MarkdownItPluginCb} from './typings'; +import {MarkdownItPluginCb} from '../typings'; import Core from 'markdown-it/lib/parser_core'; import Token from 'markdown-it/lib/token'; import {bold} from 'chalk'; diff --git a/src/transform/plugins/changelog/types.ts b/src/transform/plugins/changelog/types.ts new file mode 100644 index 00000000..e85ead75 --- /dev/null +++ b/src/transform/plugins/changelog/types.ts @@ -0,0 +1,11 @@ +export interface ChangelogItem { + title: string; + image: { + src: string; + alt: string; + ratio?: string; + }; + description: string; + date: string; + [x: string]: unknown; +} diff --git a/src/transform/plugins/typings.ts b/src/transform/plugins/typings.ts index e98e1415..3a22af81 100644 --- a/src/transform/plugins/typings.ts +++ b/src/transform/plugins/typings.ts @@ -12,15 +12,3 @@ export interface MarkdownItPluginOpts { export type MarkdownItPluginCb = { (md: MarkdownIt, opts: T & MarkdownItPluginOpts): void; }; - -export interface ChangeLogItem { - title: string; - image: { - src: string; - alt: string; - ratio?: string; - }; - description: string; - date: string; - [x: string]: unknown; -} diff --git a/src/transform/typings.ts b/src/transform/typings.ts index 33658fa6..7857a564 100644 --- a/src/transform/typings.ts +++ b/src/transform/typings.ts @@ -2,8 +2,9 @@ import {LanguageFn} from 'highlight.js'; import DefaultMarkdownIt from 'markdown-it'; import DefaultStateCore from 'markdown-it/lib/rules_core/state_core'; import {SanitizeOptions} from './sanitize'; -import {ChangeLogItem, MarkdownItPluginCb} from './plugins/typings'; +import {MarkdownItPluginCb} from './plugins/typings'; import {LogLevels} from './log'; +import {ChangelogItem} from './plugins/changelog/types'; export interface MarkdownIt extends DefaultMarkdownIt { assets?: string[]; @@ -59,5 +60,5 @@ export type EnvType = { headings: Heading[]; assets?: unknown[]; meta?: object; - changelogs?: ChangeLogItem[]; + changelogs?: ChangelogItem[]; } & Extras; diff --git a/test/changelog.test.ts b/test/changelog.test.ts index 7c9bfc34..569f614e 100644 --- a/test/changelog.test.ts +++ b/test/changelog.test.ts @@ -2,7 +2,10 @@ import transform from '../src/transform'; import path from 'path'; import fs from 'fs'; import changelogPlugin from '../src/transform/plugins/changelog'; +import changelogCollect from '../src/transform/plugins/changelog/collect'; import imsize from '../src/transform/plugins/imsize'; +import {Logger} from '../src/transform/log'; +import {ChangelogItem} from '../src/transform/plugins/changelog/types'; describe('Changelog', () => { test('Should cut changelog', async () => { @@ -50,4 +53,28 @@ describe('Changelog', () => { }), ); }); + + test('Should cut changelog and write it in variable', async () => { + expect.assertions(2); + + const data = await fs.promises.readFile(path.join(__dirname, 'data/changelog.md'), 'utf8'); + + const changelogs: ChangelogItem[] = []; + const html = changelogCollect(data, { + path: '', + changelogs, + log: console as unknown as Logger, + }); + + expect(html).toBe(`# Some changelog + + + + + +After changelog +`); + + expect(changelogs.length).toBe(3); + }); }); diff --git a/test/liquid/chaneglogs.test.ts b/test/liquid/chaneglogs.test.ts deleted file mode 100644 index faaabd4c..00000000 --- a/test/liquid/chaneglogs.test.ts +++ /dev/null @@ -1,25 +0,0 @@ -import changelogs from '../../src/transform/liquid/changelogs'; -import fs from 'fs'; -import path from 'path'; - -describe('Changelogs', () => { - test('Should cut changelogs and return changelogs', async () => { - expect.assertions(2); - - const data = await fs.promises.readFile( - path.join(__dirname, '../data/changelog.md'), - 'utf8', - ); - - const {output, changelogs: logs} = changelogs(data, {}); - expect(output).toBe(`# Some changelog - - - - - -After changelog -`); - expect(logs.length).toBe(3); - }); -}); From 1c3ac5947bf4ca79bfa3222ed8c2b578a49192d9 Mon Sep 17 00:00:00 2001 From: Anton Vikulov Date: Tue, 23 May 2023 16:04:23 +0500 Subject: [PATCH 8/8] use low case --- src/transform/plugins/changelog/collect.ts | 2 +- src/transform/plugins/changelog/index.ts | 2 +- test/changelog.test.ts | 2 +- test/data/changelog.md | 6 +++--- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/transform/plugins/changelog/collect.ts b/src/transform/plugins/changelog/collect.ts index 93cc5844..0f073835 100644 --- a/src/transform/plugins/changelog/collect.ts +++ b/src/transform/plugins/changelog/collect.ts @@ -6,7 +6,7 @@ import imsize from '../imsize'; import {MarkdownItPluginOpts} from '../typings'; const BLOCK_START = '{% changelog %}'; -const BLOCK_END = '{% endChangelog %}\n'; +const BLOCK_END = '{% endchangelog %}\n'; function parseChangelogs(str: string, path?: string) { const {parse, compile, env} = initMarkdownit({ diff --git a/src/transform/plugins/changelog/index.ts b/src/transform/plugins/changelog/index.ts index f0e5febc..e99774e8 100644 --- a/src/transform/plugins/changelog/index.ts +++ b/src/transform/plugins/changelog/index.ts @@ -14,7 +14,7 @@ interface Options { } const CHANGELOG_OPEN_RE = /^\{% changelog %}/; -const CHANGELOG_CLOSE_RE = /^\{% endChangelog %}/; +const CHANGELOG_CLOSE_RE = /^\{% endchangelog %}/; function isOpenToken(tokens: Token[], i: number) { return ( diff --git a/test/changelog.test.ts b/test/changelog.test.ts index 569f614e..1a1871d5 100644 --- a/test/changelog.test.ts +++ b/test/changelog.test.ts @@ -17,7 +17,6 @@ describe('Changelog', () => { result: {html, changelogs: logs}, } = transform(data, { plugins: [changelogPlugin, imsize], - enableChangelogs: false, }); expect(html).toBe(`

Some changelog

\n

After changelog

\n`); @@ -64,6 +63,7 @@ describe('Changelog', () => { path: '', changelogs, log: console as unknown as Logger, + extractChangelogs: true, }); expect(html).toBe(`# Some changelog diff --git a/test/data/changelog.md b/test/data/changelog.md index c484713f..5aea906b 100644 --- a/test/data/changelog.md +++ b/test/data/changelog.md @@ -10,7 +10,7 @@ storyId: 123321 Change log payload -{% endChangelog %} +{% endchangelog %} {% changelog %} ``` @@ -22,7 +22,7 @@ storyId: 123321 Change log payload -{% endChangelog %} +{% endchangelog %} {% changelog %} @@ -35,6 +35,6 @@ storyId: 123321 Change log payload -{% endChangelog %} +{% endchangelog %} After changelog