diff --git a/fileTransformer.js b/fileTransformer.js new file mode 100644 index 0000000..2e8b8e2 --- /dev/null +++ b/fileTransformer.js @@ -0,0 +1,11 @@ +const fs = require('fs'); + +module.exports = { + process(src, filename, config, options) { + return ( + 'module.exports = ' + + JSON.stringify(fs.readFileSync(filename, 'utf8')) + + ';' + ); + }, +}; diff --git a/package.json b/package.json index 19fac7f..33167fa 100644 --- a/package.json +++ b/package.json @@ -12,7 +12,9 @@ "jest": "^20.0.4", "marked": "^0.3.6", "marked-terminal": "^2.0.0", - "minimist": "^1.2.0" + "marked-to-md": "^1.0.1", + "minimist": "^1.2.0", + "node-fetch": "^1.7.1" }, "devDependencies": { "babel-cli": "^6.24.1", @@ -22,5 +24,11 @@ }, "scripts": { "test": "jest" + }, + "jest": { + "transform": { + ".+\\.(js)$": "babel-jest", + ".+\\.(md)$": "/fileTransformer.js" + } } } diff --git a/src/__mocks__/keepachangelog.md b/src/__mocks__/keepachangelog.md new file mode 100644 index 0000000..b67645a --- /dev/null +++ b/src/__mocks__/keepachangelog.md @@ -0,0 +1,144 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [Unreleased] + +## [1.0.0] - 2017-06-20 +### Added +- New visual identity by @tylerfortune8. +- Version navigation. +- Links to latest released version in previous versions. +- "Why keep a changelog?" section. +- "Who needs a changelog?" section. +- "How do I make a changelog?" section. +- "Frequently Asked Questions" section. +- New "Guiding Principles" sub-section to "How do I make a changelog?". +- Simplified and Traditional Chinese translations from @tianshuo. +- German translation from @mpbzh & @Art4. +- Italian translation from @azkidenz. +- Swedish translation from @magol. +- Turkish translation from @karalamalar. +- French translation from @zapashcanon. +- Brazilian Portugese translation from @aisamu. +- Polish translation from @amielucha. +- Russian translation from @aishek. + +### Changed +- Start using "changelog" over "change log" since it's the common usage. +- Start versioning based on the current English version at 0.3.0 to help +translation authors keep things up-to-date. +- Rewrite "What makes unicorns cry?" section. +- Rewrite "Ignoring Deprecations" sub-section to clarify the ideal + scenario. +- Improve "Commit log diffs" sub-section to further argument against + them. +- Merge "Why can’t people just use a git log diff?" with "Commit log + diffs" +- Fix typos in Simplified Chinese and Traditional Chinese translations. +- Fix typos in Brazilian Portugese translation. +- Fix typos in Turkish translation. +- Fix typos in Czech translation. +- Fix typos in Swedish translation. +- Improve phrasing in French translation. +- Fix phrasing and spelling in German translation. + +### Removed +- Section about "changelog" vs "CHANGELOG". + +## [0.3.0] - 2015-12-03 +### Added +- RU translation from @aishek. +- pt-BR translation from @tallesl. +- es-ES translation from @ZeliosAriex. + +## [0.2.0] - 2015-10-06 +### Changed +- Remove exclusionary mentions of "open source" since this project can +benefit both "open" and "closed" source projects equally. + +## [0.1.0] - 2015-10-06 +### Added +- Answer "Should you ever rewrite a change log?". + +### Changed +- Improve argument against commit logs. +- Start following [SemVer](http://semver.org) properly. + +## [0.0.8] - 2015-02-17 +### Changed +- Update year to match in every README example. +- Reluctantly stop making fun of Brits only, since most of the world + writes dates in a strange way. + +### Fixed +- Fix typos in recent README changes. +- Update outdated unreleased diff link. + +## [0.0.7] - 2015-02-16 +### Added +- Link, and make it obvious that date format is ISO 8601. + +### Changed +- Clarified the section on "Is there a standard change log format?". + +### Fixed +- Fix Markdown links to tag comparison URL with footnote-style links. + +## [0.0.6] - 2014-12-12 +### Added +- README section on "yanked" releases. + +## [0.0.5] - 2014-08-09 +### Added +- Markdown links to version tags on release headings. +- Unreleased section to gather unreleased changes and encourage note +keeping prior to releases. + +## [0.0.4] - 2014-08-09 +### Added +- Better explanation of the difference between the file ("CHANGELOG") +and its function "the change log". + +### Changed +- Refer to a "change log" instead of a "CHANGELOG" throughout the site +to differentiate between the file and the purpose of the file — the +logging of changes. + +### Removed +- Remove empty sections from CHANGELOG, they occupy too much space and +create too much noise in the file. People will have to assume that the +missing sections were intentionally left out because they contained no +notable changes. + +## [0.0.3] - 2014-08-09 +### Added +- "Why should I care?" section mentioning The Changelog podcast. + +## [0.0.2] - 2014-07-10 +### Added +- Explanation of the recommended reverse chronological release ordering. + +## 0.0.1 - 2014-05-31 +### Added +- This CHANGELOG file to hopefully serve as an evolving example of a + standardized open source project CHANGELOG. +- CNAME file to enable GitHub Pages custom domain +- README now contains answers to common questions about CHANGELOGs +- Good examples and basic guidelines, including proper date formatting. +- Counter-examples: "What makes unicorns cry?" + +[Unreleased]: https://github.com/olivierlacan/keep-a-changelog/compare/v1.0.0...HEAD +[1.0.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.3.0...v1.0.0 +[0.3.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.2.0...v0.3.0 +[0.2.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.1.0...v0.2.0 +[0.1.0]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.8...v0.1.0 +[0.0.8]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.7...v0.0.8 +[0.0.7]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.6...v0.0.7 +[0.0.6]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.5...v0.0.6 +[0.0.5]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.4...v0.0.5 +[0.0.4]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.3...v0.0.4 +[0.0.3]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.2...v0.0.3 +[0.0.2]: https://github.com/olivierlacan/keep-a-changelog/compare/v0.0.1...v0.0.2 diff --git a/src/__mocks__/simple.md b/src/__mocks__/simple.md new file mode 100644 index 0000000..cab5fd2 --- /dev/null +++ b/src/__mocks__/simple.md @@ -0,0 +1,7 @@ +# CHANGELOG + +## 1.1.0 +Done more stuff + +## 1.0.0 +Done stuff diff --git a/src/file.js b/src/file.js index 4400331..6e2571e 100644 --- a/src/file.js +++ b/src/file.js @@ -1,4 +1,5 @@ import https from 'https'; +import fetch from 'node-fetch'; const FILES_TO_TEST = [ { @@ -9,6 +10,9 @@ const FILES_TO_TEST = [ type: 'github-file', fileName: 'HISTORY.md', }, + // { + // type: 'github-releases', + // }, ]; class NoFileFoundError extends Error { @@ -33,7 +37,22 @@ export function getFileContent(packageName) { `https://raw.githubusercontent.com/${packageName}/master/${fileName}` ); - resolve(result); + resolve(result, 'markdown'); + break; + + case 'github-releases': + result = await fetch( + `https://api.github.com/repos/${packageName}/releases`, + { + headers: { + 'User-Agent': 'changelog-view', + }, + } + ); + + console.log(result); + + resolve(result, 'github-release'); break; default: diff --git a/src/markdown.js b/src/markdown.js new file mode 100644 index 0000000..7b903e9 --- /dev/null +++ b/src/markdown.js @@ -0,0 +1,68 @@ +import marked from 'marked'; +import mdRenderer from 'marked-to-md'; + +function getTokens(content) { + const lexer = new marked.Lexer(); + const tokens = lexer.lex(content); + + return tokens; +} + +function getVersionFromTitle(title) { + const titleSemVerMatch = title.match(/(\d+)(?:\.(\d+)(?:\.(\d+))?)?/); + if (!titleSemVerMatch) { + return null; + } + + const [version, major, minor, patch] = titleSemVerMatch; + + return { + version, + major, + minor, + patch, + }; +} + +export function reduceTokens(tokens) { + let currentVersion = null; + return tokens.reduce((curr, token) => { + if (token.type === 'heading') { + const version = getVersionFromTitle(token.text); + if (version) { + currentVersion = version.version; + + if (!curr[currentVersion]) { + curr[currentVersion] = []; + } + } + } + + if (currentVersion) { + curr[currentVersion].push(token); + } + + return curr; + }, {}); +} + +export function convertMarkdownToVersionList(markdown) { + const out = []; + + const tokens = getTokens(markdown); + + let currentVersionToken = []; + const reducedTokens = reduceTokens(tokens); + return Object.entries(reducedTokens).map(([version, tokens]) => { + // console.log(version, tokens); + tokens.links = {}; + const content = marked.parser(tokens, { + renderer: mdRenderer(new marked.Renderer()), + }); + + return { + version, + content, + }; + }); +} diff --git a/src/markdown.test.js b/src/markdown.test.js new file mode 100644 index 0000000..4cae145 --- /dev/null +++ b/src/markdown.test.js @@ -0,0 +1,40 @@ +import simpleMarkdown from './__mocks__/simple.md'; +import { reduceTokens, convertMarkdownToVersionList } from './markdown'; + +describe('markdown to version list converter', () => { + test('reduce tokens', () => { + const tokens = [ + { type: 'heading', depth: 1, text: 'CHANGELOG' }, + { type: 'heading', depth: 2, text: '1.1.0' }, + { type: 'paragraph', text: 'Done more stuff' }, + { type: 'heading', depth: 2, text: '1.0.0' }, + { type: 'paragraph', text: 'Done stuff' }, + ]; + + expect(reduceTokens(tokens)).toEqual({ + '1.1.0': [ + { type: 'heading', depth: 2, text: '1.1.0' }, + { type: 'paragraph', text: 'Done more stuff' }, + ], + '1.0.0': [ + { type: 'heading', depth: 2, text: '1.0.0' }, + { type: 'paragraph', text: 'Done stuff' }, + ], + }); + }); + + test('convert simple markdown to a version list', () => { + expect(convertMarkdownToVersionList(simpleMarkdown)).toEqual([ + { + version: '1.1.0', + content: '## 1.1.0\nDone more stuff\n\n', + }, + { + version: '1.0.0', + content: '## 1.0.0\nDone stuff\n\n', + }, + ]); + }); + + test('convert keepachangelog.com changelog to a version list', () => {}); +}); diff --git a/src/tokens.js b/src/tokens.js index 83d8b81..bfb5631 100644 --- a/src/tokens.js +++ b/src/tokens.js @@ -33,7 +33,10 @@ export function findContent(content, version) { for (let i = 0; i < tokens.length; i++) { const token = tokens[i]; - if (token.type === 'heading' && titleMatchCurrentVersion(token.text, version)) { + if ( + token.type === 'heading' && + titleMatchCurrentVersion(token.text, version) + ) { break; } @@ -51,4 +54,3 @@ function getTokens(content) { return tokens; } - diff --git a/yarn.lock b/yarn.lock index c976659..b42c0f2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -978,6 +978,12 @@ electron-to-chromium@^1.3.16: version "1.3.16" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.16.tgz#d0e026735754770901ae301a21664cba45d92f7d" +encoding@^0.1.11: + version "0.1.12" + resolved "https://registry.yarnpkg.com/encoding/-/encoding-0.1.12.tgz#538b66f3ee62cd1ab51ec323829d1f9480c74beb" + dependencies: + iconv-lite "~0.4.13" + errno@^0.1.4: version "0.1.4" resolved "https://registry.yarnpkg.com/errno/-/errno-0.1.4.tgz#b896e23a9e5e8ba33871fc996abd3635fc9a1c7d" @@ -1321,6 +1327,10 @@ iconv-lite@0.4.13: version "0.4.13" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.13.tgz#1f88aba4ab0b1508e8312acc39345f36e992e2f2" +iconv-lite@~0.4.13: + version "0.4.18" + resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.18.tgz#23d8656b16aae6742ac29732ea8f0336a4789cf2" + inflight@^1.0.4: version "1.0.6" resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" @@ -1428,6 +1438,10 @@ is-primitive@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/is-primitive/-/is-primitive-2.0.0.tgz#207bab91638499c07b2adf240a41a87210034575" +is-stream@^1.0.1: + version "1.1.0" + resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44" + is-typedarray@~1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" @@ -1894,6 +1908,10 @@ marked-terminal@^2.0.0: lodash.assign "^4.2.0" node-emoji "^1.4.1" +marked-to-md@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/marked-to-md/-/marked-to-md-1.0.1.tgz#864cacb02f3f0a92510c53a8d5fa1e14acd09a5f" + marked@^0.3.6: version "0.3.6" resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.6.tgz#b2c6c618fccece4ef86c4fc6cb8a7cbf5aeda8d7" @@ -1994,6 +2012,13 @@ node-emoji@^1.4.1: dependencies: lodash.toarray "^4.4.0" +node-fetch@^1.7.1: + version "1.7.1" + resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-1.7.1.tgz#899cb3d0a3c92f952c47f1b876f4c8aeabd400d5" + dependencies: + encoding "^0.1.11" + is-stream "^1.0.1" + node-int64@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"