Compare commits

..

299 commits

Author SHA1 Message Date
Rodrigo Fernandes
1350740c98
fix artifacts 2024-12-23 23:17:59 +00:00
Rodrigo Fernandes
04640cccbe
force release 2024-12-23 23:08:34 +00:00
Rodrigo Fernandes
babcdb0405
Merge pull request #551 from rtfpessoa/bump-dependencies
Bump dependencies
2024-12-23 22:55:42 +00:00
Rodrigo Fernandes
2f4f41a31d
bump node version 2024-12-23 22:52:07 +00:00
Rodrigo Fernandes
2f8c477f66
fix build 2024-12-23 22:49:18 +00:00
Rodrigo Fernandes
064659a70e
update tests 2024-12-23 22:41:43 +00:00
Rodrigo Fernandes
eef651f0d4
bump more versions 2024-12-23 22:34:58 +00:00
Rodrigo Fernandes
d67d80eb41
fix dark demo theme and bump deps 2024-07-20 22:46:00 +01:00
Rodrigo Fernandes
a88e4b3ba4
bump more versions 2024-07-09 18:35:22 +01:00
Rodrigo Fernandes
dbdd2e9c26
bump bulma 2024-07-09 18:30:45 +01:00
Rodrigo Fernandes
05fbd33a3a
fix output directories 2024-07-09 18:19:04 +01:00
Rodrigo Fernandes
b2e31b6083
bump more dependencies 2024-07-05 23:59:55 +01:00
Rodrigo Fernandes
00a12d11aa
bump dependencies 2024-07-05 23:52:51 +01:00
Rodrigo Fernandes
b517e40e5c
Merge pull request #531 from rtfpessoa/use-npm
use npm instead of yarn
2024-04-19 21:39:35 +01:00
Rodrigo Fernandes
dea1d300b3
use npm instead of yarn 2024-04-19 21:35:17 +01:00
Rodrigo Fernandes
4de87bf099
Merge pull request #523 from rtfpessoa/bump-dependencies
updates
2024-01-12 20:15:25 +00:00
Rodrigo Fernandes
aa4731953e
updates 2024-01-12 20:09:44 +00:00
Rodrigo Fernandes
363b619d87
Merge pull request #518 from JeroenVdb/support-shadow-dom
css: target both :root and :host to also cover usage in shadow DOM
2023-12-15 21:38:49 +00:00
Jeroen Van den Berghe
7005ced0b5 css: target both :root and :host to also cover usage in shadow DOM
Inside shadow DOM :root can't be targeted, so :host should be used here for those cases.

Solves issues #517
2023-10-17 13:26:41 +02:00
Rodrigo Fernandes
99b7757a3a
Merge pull request #515 from akwiatek/update-dark-mode-css
Amend malformed CSS.
2023-10-05 16:17:34 +01:00
Adam Kwiatek
dd4b774958 Amend malformed CSS. 2023-10-02 17:48:24 +02:00
Rodrigo Fernandes
b04a400329
Merge pull request #514 from JHWelch/add-dark-mode
Add Dark & Auto color schemes
2023-09-29 20:13:49 +01:00
Jordan Welch
7410d25ee4
Use d2h-light-color-scheme for light 2023-09-26 18:06:06 -05:00
Jordan Welch
987d8cb65c
update to GitHub dark colors 2023-09-26 17:47:59 -05:00
Jordan Welch
d425892b61
Remove duplicate "should"s 2023-09-20 08:02:40 -05:00
Jordan Welch
f7aacc4fc0
darken header 2023-09-19 20:54:19 -05:00
Jordan Welch
0de1e040b0
Create modified github theme for demo 2023-09-19 20:51:38 -05:00
Jordan Welch
4b42e4b0de
Toggle colorscheme on Demo body 2023-09-19 20:46:45 -05:00
Jordan Welch
863246eed0
remove redundant classes 2023-09-19 20:18:35 -05:00
Jordan Welch
3865a5f27e
Adjust colors 2023-09-19 19:54:40 -05:00
Jordan Welch
b26353c04d
Normalize remaining variables 2023-09-19 19:47:17 -05:00
Jordan Welch
8d9a8a8265
Fix --d2h-dark-moved-label-color references 2023-09-19 19:04:06 -05:00
Jordan Welch
1aa822da56
Update test text 2023-09-19 19:04:06 -05:00
Jordan Welch
786e5cc027
Fix remaining --d2h-dark-line-border-color 2023-09-19 19:04:06 -05:00
Jordan Welch
9806d677f3
Add file header 2023-09-19 19:04:05 -05:00
Jordan Welch
efd28ffb3a
Move dark variables and match pattern 2023-09-19 19:04:05 -05:00
Jordan Welch
93103e2c49
Convert light colors to variables 2023-09-19 19:04:05 -05:00
Jordan Welch
0029890ead
Add colorScheme information to README 2023-09-19 19:04:05 -05:00
Jordan Welch
79268800ff
Add colors for file list 2023-09-19 19:04:04 -05:00
Jordan Welch
9f8d6bd4ca
Pass config to file list renderer 2023-09-19 19:04:04 -05:00
Jordan Welch
669ee2bff8
Fix del/ins change colors 2023-09-19 19:04:03 -05:00
Jordan Welch
0dccfa26a5
Pass default from default render config 2023-09-19 19:04:03 -05:00
Jordan Welch
c244b0dd51
Add ColorSchemeType for file list 2023-09-19 19:04:03 -05:00
Jordan Welch
4e6bb49788
Update FileListRenderer to class 2023-09-19 19:04:02 -05:00
Jordan Welch
14989f1ddd
rename test to match Class & function 2023-09-19 19:04:02 -05:00
Jordan Welch
58c088977e
Fix color preference order 2023-09-19 19:04:02 -05:00
Jordan Welch
c22febdbd6
Adjust colors for line-by-line 2023-09-19 19:04:01 -05:00
Jordan Welch
1b0c1a87a2
swap highlight and base 2023-09-19 19:04:01 -05:00
Jordan Welch
84a323f0de
Add color scheme to demo page 2023-09-19 19:04:01 -05:00
Jordan Welch
0b76161d86
Use variables for dark mode 2023-09-19 19:04:00 -05:00
Jordan Welch
6ed6a5da88
Setup Auto color mode 2023-09-19 19:04:00 -05:00
Jordan Welch
47000723a9
Consolidate dark classes 2023-09-19 19:04:00 -05:00
Jordan Welch
6b420de752
est auto color scheme 2023-09-19 19:03:59 -05:00
Jordan Welch
bd4a84cd3e
Update colors 2023-09-19 19:03:59 -05:00
Jordan Welch
1aafcb201b
Add dark mode classes. 2023-09-19 19:03:59 -05:00
Jordan Welch
4d2505dac8
Normalize class names 2023-09-19 19:03:59 -05:00
Jordan Welch
ff3a86d393
Add colorscheme variable to wrapper 2023-09-19 19:03:58 -05:00
Jordan Welch
5dae945e95
Add initial dark mode css classes 2023-09-19 19:03:57 -05:00
Rodrigo Fernandes
8102d3cf61
Merge pull request #511 from JHWelch/organize-diff2html-tests
reorganize/rename blocks to match tested functions
2023-09-19 22:31:14 +01:00
Rodrigo Fernandes
2ffca85422
Merge pull request #512 from reustle/docs-typo-fix
Docs typo fix
2023-09-19 22:30:35 +01:00
Shane Reustle
299f7800c3
Docs typo fix 2023-09-12 19:55:53 -04:00
Jordan Welch
66912a3a54
reorganize/rename blocks to match tested functions 2023-09-11 22:48:23 -05:00
Rodrigo Fernandes
3732d59249
Merge pull request #508 from minami80630/fix-link
fix broken link
2023-09-01 23:59:19 +01:00
Rodrigo Fernandes
412928fc59
Merge pull request #507 from shoito/fix-start-website
fix 'yarn start:website' command
2023-09-01 23:58:52 +01:00
minami80630
61695e2896 fix broken link 2023-09-01 10:45:58 +09:00
shoito
93d0fbc6c3 fix 'yarn start:website' command 2023-08-30 21:38:18 +09:00
Rodrigo Fernandes
61d90c1c41
Merge pull request #506 from rtfpessoa/fix-error-unloaded-lang
fallback to plaintext when highlighting unloaded language
2023-08-27 21:40:19 +01:00
Rodrigo Fernandes
f6f05db2f6
fallback to plaintext when highlighting unloaded language 2023-08-27 21:37:39 +01:00
Rodrigo Fernandes
41a901694d
Merge pull request #503 from rtfpessoa/remove-import-helpers
Do not use import helpers
2023-08-07 10:23:40 +01:00
Rodrigo Fernandes
3516684c68
Do not use import helpers 2023-08-07 09:52:31 +01:00
Rodrigo Fernandes
638a4a286f
Merge pull request #500 from rtfpessoa/bump-deps
fix vuln
2023-08-06 19:52:13 +01:00
Rodrigo Fernandes
9d805bb021 fix vuln 2023-08-06 19:44:36 +01:00
Rodrigo Fernandes
8d34de633a
Merge pull request #499 from rtfpessoa/bump-deps
Bump deps
2023-08-06 19:32:04 +01:00
Rodrigo Fernandes
409b5e2f6b tweak tsconfig 2023-08-06 19:28:46 +01:00
Rodrigo Fernandes
657d48aac0 bump deps 2023-08-06 19:16:10 +01:00
Rodrigo Fernandes
611957e270
Merge pull request #498 from rtfpessoa/update-readme
fix badges
2023-08-06 19:09:58 +01:00
Rodrigo Fernandes
dfe2eec8df fix badges 2023-08-06 19:09:07 +01:00
Rodrigo Fernandes
40a9c0bdc8
Merge pull request #497 from rtfpessoa/update-readme
fix badges
2023-08-06 19:07:01 +01:00
Rodrigo Fernandes
a2d34e195c fix badges 2023-08-06 19:06:31 +01:00
Rodrigo Fernandes
e46184baa2
Merge pull request #488 from rtfpessoa/fix-vertical-align
fix vertical align on diff
2023-04-15 14:15:16 +01:00
Rodrigo Fernandes
7a3a4398d1 fix vertical align on diff 2023-04-15 14:12:08 +01:00
Rodrigo Fernandes
2c7e03d266
Merge pull request #486 from rtfpessoa/dependabot/npm_and_yarn/webpack-5.76.0
build(deps-dev): bump webpack from 5.74.0 to 5.76.0
2023-03-16 23:25:59 +00:00
dependabot[bot]
c76b24a1fd
build(deps-dev): bump webpack from 5.74.0 to 5.76.0
Bumps [webpack](https://github.com/webpack/webpack) from 5.74.0 to 5.76.0.
- [Release notes](https://github.com/webpack/webpack/releases)
- [Commits](https://github.com/webpack/webpack/compare/v5.74.0...v5.76.0)

---
updated-dependencies:
- dependency-name: webpack
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-03-15 06:20:11 +00:00
Rodrigo Fernandes
68515376a1
Merge pull request #483 from phikes/hand-in-file-line-to-template
feat: hand in file/line to generic line template
2023-03-07 19:34:03 +00:00
Rodrigo Fernandes
551a0b407f
Merge pull request #482 from grimsteel/patch-1
Precise widths for `code-line` and `code-side-line`
2023-03-04 23:40:54 +00:00
Siddhant
32239a0b9d
Precise widths for code-line and code-side-line
The widths of these are now calculated based on:
100% minus the horizontal padding
2023-02-28 19:17:07 -06:00
Phillip Kessels
0d314aecd1
feat: hand in file/line to generic line template 2023-02-20 15:07:34 +00:00
Rodrigo Fernandes
09cbe87595
Merge pull request #478 from rtfpessoa/support-unix-diff-binaries
support unix diff binaires
2023-01-20 23:06:53 +00:00
Rodrigo Fernandes
a716739a18 support unix diff binaires 2023-01-20 23:00:34 +00:00
Rodrigo Fernandes
24ccfefa26
Merge pull request #477 from rtfpessoa/fix-firefox
fix-broken-header-ff
2023-01-20 22:32:05 +00:00
Rodrigo Fernandes
ca2397830c fix-broken-header-ff 2023-01-20 22:27:44 +00:00
Rodrigo Fernandes
66c305b854
Merge pull request #471 from rtfpessoa/tweak-css
fix home page link
2023-01-06 23:38:19 +00:00
Rodrigo Fernandes
be09a43715 fix home page link 2023-01-06 23:37:55 +00:00
Rodrigo Fernandes
d2e3705575
Merge pull request #470 from rtfpessoa/tweak-css
tweak css
2023-01-06 23:33:24 +00:00
Rodrigo Fernandes
d0ead3a14c tweak css 2023-01-06 23:32:58 +00:00
Rodrigo Fernandes
9247496115
Merge pull request #463 from FurcyPin/fpin/462
fix #462: Info lines shrunk in right panel of side-by-side diff
2023-01-06 23:29:07 +00:00
Rodrigo Fernandes
432901db33
Merge pull request #469 from rtfpessoa/test-actions
reorder
2023-01-06 23:24:18 +00:00
Rodrigo Fernandes
838bdf6095 reorder 2023-01-06 23:24:02 +00:00
Rodrigo Fernandes
7d173d5f4c
Merge pull request #468 from rtfpessoa/test-actions
fix env
2023-01-06 23:01:00 +00:00
Rodrigo Fernandes
897447d7d7 fix env 2023-01-06 23:00:41 +00:00
Rodrigo Fernandes
37caf65775
Merge pull request #467 from rtfpessoa/test-actions
Merge pull request #466 from rtfpessoa/test-actions
2023-01-06 22:45:47 +00:00
Rodrigo Fernandes
be4b1d0624 Merge pull request #466 from rtfpessoa/test-actions
fix s3 upload
2023-01-06 22:44:58 +00:00
Rodrigo Fernandes
1cc02ff4e1
Merge pull request #466 from rtfpessoa/test-actions
fix s3 upload
2023-01-06 22:38:28 +00:00
Rodrigo Fernandes
7e37ce307a fix s3 upload 2023-01-06 22:37:33 +00:00
Rodrigo Fernandes
81b0f67107
Merge pull request #465 from rtfpessoa/test-actions
fix s3 upload
2023-01-06 22:18:15 +00:00
Rodrigo Fernandes
51cd7854f9 fix s3 upload 2023-01-06 22:17:52 +00:00
Rodrigo Fernandes
88b06ef3e3
Merge pull request #464 from rtfpessoa/test-actions
Migrate to GitHub Actions
2023-01-06 21:58:30 +00:00
Rodrigo Fernandes
c89192a37f wip 2023-01-06 21:49:15 +00:00
fpin
df005c3f06 fix #462: Info lines shrunk in right panel of side-by-side diff 2023-01-02 16:17:16 +01:00
Rodrigo Fernandes
7cd6bb9aff
Merge pull request #459 from rtfpessoa/dependabot/npm_and_yarn/decode-uri-component-0.2.2
build(deps): bump decode-uri-component from 0.2.0 to 0.2.2
2023-01-01 22:26:46 +00:00
dependabot[bot]
1167be6add
build(deps): bump decode-uri-component from 0.2.0 to 0.2.2
Bumps [decode-uri-component](https://github.com/SamVerschueren/decode-uri-component) from 0.2.0 to 0.2.2.
- [Release notes](https://github.com/SamVerschueren/decode-uri-component/releases)
- [Commits](https://github.com/SamVerschueren/decode-uri-component/compare/v0.2.0...v0.2.2)

---
updated-dependencies:
- dependency-name: decode-uri-component
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-12-03 07:28:59 +00:00
Rodrigo Fernandes
7b6ee267af
Merge pull request #458 from ericcornelissen/check-hljs-once
Check if hljs is not null only once
2022-11-04 23:46:45 +00:00
Eric Cornelissen
3a480e4ab0 perf: check hljs is not null only once
Update the `highlightCode` method of `Diff2HtmlUI` to check if the hljs
reference is null only once (at the start). This address the "HACK"
comments by using a locally scoped variable for hljs. This way,
TypeScript is able to deduce that, after the initial null-check, hljs is
in fact not null.
2022-11-02 22:43:23 +01:00
Rodrigo Fernandes
6db4aae9e5
Merge pull request #456 from ericcornelissen/455-sticky-file-headers
Implement support for sticky file headers
2022-11-01 00:14:45 +00:00
Eric Cornelissen
4dae65d5c7 feat: enable sticky file headers by default
Update the stickyFileHeaders default value to `true` so that it is
enabled by default. Also correct the name of this option in the
documentation by adding the missing trailing "s".
2022-10-31 09:47:31 +01:00
Rodrigo Fernandes
35008fba4b
Merge pull request #457 from rtfpessoa/fix-side-by-side-margins-highlight-overrides
fix side by side margins and highlight usage of object instead of map
2022-10-30 20:34:38 +00:00
Rodrigo Fernandes
5ca9d22276 fix side by side margins and highlight usage of object instead of map 2022-10-30 20:31:33 +00:00
Eric Cornelissen
7d4a5dce6f feat: sticky file headers
Add support for sticky file headers by adding a `stickyFileHeaders`
option to the `Diff2HtmlUI`. By default this feature is disabled. Also
document this option in the README.

The feature is implemented through an optional CSS class on top of the
pre-existing `.d2h-file-header` class. The new class is added on all
file headers if the option is set to `true` (or the `stickyFileHeaders`
method is called).

This class, `.d2h-sticky-header`, has the minimum amount of styling to
get the desired effect. The `position` and `top` values make the headers
stick to the top as long as the wrapper is in the view. The `z-index`
value is needed to ensure the header is displayed over all other content
in the wrapper. In particular, from my testing in Firefox (106.0.2), the
line numbers would display over the header if the `z-index` value isn't
set.
2022-10-30 13:05:53 +01:00
Rodrigo Fernandes
59ff2956ab
Merge pull request #453 from rtfpessoa/fix-s3-website-release
fix website release
2022-10-23 18:42:22 +01:00
Rodrigo Fernandes
1a7612c0ff fix website release 2022-10-23 18:40:35 +01:00
Rodrigo Fernandes
86f43ba5ae
Merge pull request #452 from rtfpessoa/bump-deps
bump deps
2022-10-23 18:35:14 +01:00
Rodrigo Fernandes
f9d328e9b8
Merge pull request #451 from rtfpessoa/support-language-override
add support for language override
2022-10-23 18:35:04 +01:00
Rodrigo Fernandes
35e518fe4f bump deps 2022-10-23 18:31:07 +01:00
Rodrigo Fernandes
5373ae180b add support for language override 2022-10-23 18:26:19 +01:00
Rodrigo Fernandes
95e4c40a30
Merge pull request #450 from rtfpessoa/bump-deps
bump dependencies
2022-10-16 01:10:10 +01:00
Rodrigo Fernandes
a09d50a94f bump dependencies 2022-10-16 00:01:01 +01:00
Rodrigo Fernandes
26adbdb220
Merge pull request #447 from phaseOne/patch-1
Fix file collapse UI regression
2022-09-02 22:01:33 +01:00
Evan Bovie
a3a0385991 fix prettier complaint 2022-08-25 19:51:21 +00:00
Evan Bovie
a5e2fab2f1
Fix file collapse UI regression
Increase specificity of .d2h-d-none selector
2022-08-25 12:09:43 -07:00
Rodrigo Fernandes
0ed9e76a35
Merge pull request #444 from rtfpessoa/bump-deps
update dependencies
2022-07-24 18:57:20 +01:00
Rodrigo Fernandes
82a2da0033 update node versions 2022-07-24 18:49:57 +01:00
Rodrigo Fernandes
b164b511d8
Merge pull request #441 from m-masaki72/feature/set-parent-class-to-flex
Set display:flex to align inline-block elements
2022-07-24 18:34:43 +01:00
Rodrigo Fernandes
31a418601b force semver-regex update 2022-07-24 18:27:00 +01:00
Rodrigo Fernandes
93a53cdb4e force tercer update 2022-07-24 18:18:38 +01:00
Rodrigo Fernandes
1c59463034 update dependencies 2022-07-24 18:16:51 +01:00
森 雅希
41037b20f3 Set display:flex to align inline-block elements 2022-07-13 19:16:07 +09:00
Rodrigo Fernandes
e5c813949f
Merge pull request #432 from rtfpessoa/bump-deps
bump dependencies
2022-04-15 21:22:17 +01:00
Rodrigo Fernandes
4b9114afe5 bump node versions 2022-04-15 21:19:20 +01:00
Rodrigo Fernandes
7e3c867d74 bump dependencies 2022-04-15 21:05:09 +01:00
Rodrigo Fernandes
57ff821635
Merge pull request #431 from rtfpessoa/dependabot/npm_and_yarn/minimist-1.2.6
build(deps): bump minimist from 1.2.5 to 1.2.6
2022-04-15 20:27:05 +01:00
Rodrigo Fernandes
50806ba4e7
Merge pull request #429 from rtfpessoa/dependabot/npm_and_yarn/node-forge-1.3.0
build(deps): bump node-forge from 1.2.1 to 1.3.0
2022-04-15 20:26:52 +01:00
dependabot[bot]
1275853d62
build(deps): bump minimist from 1.2.5 to 1.2.6
Bumps [minimist](https://github.com/substack/minimist) from 1.2.5 to 1.2.6.
- [Release notes](https://github.com/substack/minimist/releases)
- [Commits](https://github.com/substack/minimist/compare/1.2.5...1.2.6)

---
updated-dependencies:
- dependency-name: minimist
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-04-10 09:38:43 +00:00
dependabot[bot]
95006629ec
build(deps): bump node-forge from 1.2.1 to 1.3.0
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 1.2.1 to 1.3.0.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/v1.2.1...v1.3.0)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-03-23 13:15:06 +00:00
Rodrigo Fernandes
e08596da35
Merge pull request #426 from rtfpessoa/rtfpessoa-patch-1
Add git-tabular-diff atom plugin to website
2022-02-09 21:53:10 +00:00
Rodrigo Fernandes
1f61965110
Add git-tabular-diff atom plugin to website 2022-02-09 21:53:02 +00:00
Rodrigo Fernandes
4067ecdb92
Merge pull request #425 from rtfpessoa/dependabot/npm_and_yarn/node-fetch-2.6.7
build(deps): bump node-fetch from 2.6.5 to 2.6.7
2022-01-30 17:39:47 +00:00
Rodrigo Fernandes
e1f641748a fix markdown formatting 2022-01-30 17:35:12 +00:00
dependabot[bot]
f5e1437f34
build(deps): bump node-fetch from 2.6.5 to 2.6.7
Bumps [node-fetch](https://github.com/node-fetch/node-fetch) from 2.6.5 to 2.6.7.
- [Release notes](https://github.com/node-fetch/node-fetch/releases)
- [Commits](https://github.com/node-fetch/node-fetch/compare/v2.6.5...v2.6.7)

---
updated-dependencies:
- dependency-name: node-fetch
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-30 17:30:06 +00:00
Rodrigo Fernandes
c541b98e14
Merge pull request #423 from rtfpessoa/dependabot/npm_and_yarn/nanoid-3.2.0
build(deps): bump nanoid from 3.1.23 to 3.2.0
2022-01-30 17:25:22 +00:00
Rodrigo Fernandes
bc6ca55e8d
Update README.md 2022-01-28 23:14:42 +00:00
dependabot[bot]
2466a74fec
build(deps): bump nanoid from 3.1.23 to 3.2.0
Bumps [nanoid](https://github.com/ai/nanoid) from 3.1.23 to 3.2.0.
- [Release notes](https://github.com/ai/nanoid/releases)
- [Changelog](https://github.com/ai/nanoid/blob/main/CHANGELOG.md)
- [Commits](https://github.com/ai/nanoid/compare/3.1.23...3.2.0)

---
updated-dependencies:
- dependency-name: nanoid
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-22 01:08:50 +00:00
Rodrigo Fernandes
973842064c
Merge pull request #420 from rtfpessoa/dependabot/npm_and_yarn/node-forge-1.2.1
build(deps): bump node-forge from 0.10.0 to 1.2.1
2022-01-14 21:58:27 +00:00
dependabot[bot]
05c2915e59
build(deps): bump node-forge from 0.10.0 to 1.2.1
Bumps [node-forge](https://github.com/digitalbazaar/forge) from 0.10.0 to 1.2.1.
- [Release notes](https://github.com/digitalbazaar/forge/releases)
- [Changelog](https://github.com/digitalbazaar/forge/blob/main/CHANGELOG.md)
- [Commits](https://github.com/digitalbazaar/forge/compare/0.10.0...v1.2.1)

---
updated-dependencies:
- dependency-name: node-forge
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2022-01-14 18:38:56 +00:00
Rodrigo Fernandes
b0c5a70216
Merge pull request #419 from aantn/master
Add Robusta to list of projects using diff2html
2021-12-29 12:04:36 +00:00
Natan Yellin
2f832aa610
Add Robusta to list of projects using diff2html 2021-12-28 22:27:59 +02:00
Rodrigo Fernandes
6b2b9de2c2
Merge pull request #416 from bmuskalla/patch-1
Fix broken link to documentation
2021-11-26 22:36:54 +00:00
Benjamin Muskalla
1d5c2b67f2
Fix broken link to documentation
Fixes duplicate closing tag (which made the link not usable at all) and linked readme section to jump directly to docs
2021-11-25 16:40:41 +01:00
Rodrigo Fernandes
68395e5562
Merge pull request #413 from rtfpessoa/update-contributors
Update contributors
2021-10-29 23:01:28 +02:00
Rodrigo Fernandes
d7fbb14ac6 Add @dependabot-preview[bot] as a contributor 2021-10-29 22:59:56 +02:00
Rodrigo Fernandes
206919b836 Add @campersau as a contributor 2021-10-29 22:59:45 +02:00
Rodrigo Fernandes
a77a8def37 Update @escitalopram as a contributor 2021-10-29 22:58:18 +02:00
Rodrigo Fernandes
ac47539d09 Update @dickeylth as a contributor 2021-10-29 22:57:36 +02:00
Rodrigo Fernandes
295d1fe156 Update @sss0791 as a contributor 2021-10-29 22:57:22 +02:00
Rodrigo Fernandes
182250152f Update @pubkey as a contributor 2021-10-29 22:57:11 +02:00
Rodrigo Fernandes
1b4420cadd Update @romellem as a contributor 2021-10-29 22:57:02 +02:00
Rodrigo Fernandes
b141f14762 Update @wesssel as a contributor 2021-10-29 22:56:53 +02:00
Rodrigo Fernandes
ad2314549a Update @dsabanin as a contributor 2021-10-29 22:56:44 +02:00
Rodrigo Fernandes
c04489d624 Update @starpit as a contributor 2021-10-29 22:56:26 +02:00
Rodrigo Fernandes
db07f271d6 Update @kaishuu0123 as a contributor 2021-10-29 22:55:42 +02:00
Rodrigo Fernandes
60b7eb80f5 Add @timgates42 as a contributor 2021-10-29 22:55:13 +02:00
Rodrigo Fernandes
31318145e7 Add @xlith as a contributor 2021-10-29 22:54:56 +02:00
Rodrigo Fernandes
7a042fdd6b Update @Pierrci as a contributor 2021-10-29 22:54:45 +02:00
Rodrigo Fernandes
abb9064e11 Add @Pierrci as a contributor 2021-10-29 22:54:32 +02:00
Rodrigo Fernandes
bba6114a86 Add @charguer as a contributor 2021-10-29 22:54:14 +02:00
Rodrigo Fernandes
c8901b5796 Add @domdomegg as a contributor 2021-10-29 22:53:55 +02:00
Rodrigo Fernandes
45e6f9f266 Update @mohd-akram as a contributor 2021-10-29 22:53:23 +02:00
Rodrigo Fernandes
b49cad2290 Add @pgrimaud as a contributor 2021-10-29 22:52:46 +02:00
Rodrigo Fernandes
561a7f9efa doc: add apeckham to contributors 2021-10-29 22:51:40 +02:00
Rodrigo Fernandes
d3859b8088
Merge pull request #412 from apeckham/patch-1
Fix indentation in Diff2HtmlUI example
2021-10-21 15:11:44 +01:00
Aaron
c6ccf02623
Fix indentation in Diff2HtmlUI example 2021-10-20 15:51:39 -07:00
Rodrigo Fernandes
7ef1a6f9a5
Merge pull request #411 from rtfpessoa/update-users
docs: Update user list
2021-10-16 00:12:26 +01:00
Rodrigo Fernandes
f8ea8a73b7
docs: Update user list 2021-10-16 00:11:10 +01:00
Rodrigo Fernandes
d262ff2176
Merge pull request #409 from rtfpessoa/dependabot/npm_and_yarn/nth-check-2.0.1
build(deps): bump nth-check from 2.0.0 to 2.0.1
2021-10-15 22:20:24 +01:00
dependabot[bot]
a9707cd9c3
build(deps): bump nth-check from 2.0.0 to 2.0.1
Bumps [nth-check](https://github.com/fb55/nth-check) from 2.0.0 to 2.0.1.
- [Release notes](https://github.com/fb55/nth-check/releases)
- [Commits](https://github.com/fb55/nth-check/compare/v2.0.0...v2.0.1)

---
updated-dependencies:
- dependency-name: nth-check
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-10-15 20:56:28 +00:00
Rodrigo Fernandes
1e0921c621
Merge pull request #408 from rtfpessoa/bump-dependencies
bump: Update all dependencies
2021-10-15 21:55:55 +01:00
Rodrigo Fernandes
72b0610d2c
bump: Update all dependencies 2021-10-15 21:29:07 +01:00
Rodrigo Fernandes
dbb27ed3b0
Merge pull request #407 from rtfpessoa/add-language-mappings
fix: Add language mappings for highlight.js
2021-10-15 21:02:25 +01:00
Rodrigo Fernandes
679e67b555
fix: Add language mappings for highlight.js 2021-10-15 20:48:14 +01:00
Rodrigo Fernandes
f788039ba0
Merge pull request #404 from rtfpessoa/dependabot/npm_and_yarn/tmpl-1.0.5
build(deps): bump tmpl from 1.0.4 to 1.0.5
2021-10-01 21:24:20 +01:00
dependabot[bot]
69987a8a7f
build(deps): bump tmpl from 1.0.4 to 1.0.5
Bumps [tmpl](https://github.com/daaku/nodejs-tmpl) from 1.0.4 to 1.0.5.
- [Release notes](https://github.com/daaku/nodejs-tmpl/releases)
- [Commits](https://github.com/daaku/nodejs-tmpl/commits/v1.0.5)

---
updated-dependencies:
- dependency-name: tmpl
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-09-21 16:01:45 +00:00
Rodrigo Fernandes
6ce9292c52
Merge pull request #402 from rtfpessoa/add-language-mappings
fix: Add language mappings for highlight.js
2021-09-03 23:32:54 +01:00
Rodrigo Fernandes
e44b4b1363
fix: Add language mappings for highlight.js 2021-09-03 23:26:31 +01:00
Rodrigo Fernandes
cfe56add8f
Merge pull request #401 from rtfpessoa/fix-sbs-file-toggle
fix: Remove display block to allow hidding file contents
2021-09-01 16:44:42 +01:00
Rodrigo Fernandes
7253dbb900 fix: Remove display block to allow hidding file contents 2021-09-01 15:39:34 +00:00
Rodrigo Fernandes
5f4b45c4b9
Merge pull request #399 from pgrimaud/master
docs: fix typos
2021-08-10 15:42:00 +01:00
Pierre Grimaud
73f7d4304b
docs: fix typos 2021-08-10 13:01:33 +02:00
Rodrigo Fernandes
04b598599a
Merge pull request #383 from rtfpessoa/bump-dependencies
Bump dependencies
2021-07-23 21:54:22 +01:00
Rodrigo Fernandes
6572b68bf2
bump: Update dependencies 2021-07-23 21:50:00 +01:00
Rodrigo Fernandes
b8594e1994
Merge pull request #396 from rtfpessoa/improve-git-diff-support
clean: Improve git diff support
2021-07-09 22:39:41 +01:00
Rodrigo Fernandes
6ad7f00be2
clean: Improve git diff support 2021-07-09 22:35:27 +01:00
Rodrigo Fernandes
9987e7c695
doc: Add docs about the input format 2021-07-09 22:27:06 +01:00
Rodrigo Fernandes
239d943fad
Merge pull request #395 from rtfpessoa/dependabot/npm_and_yarn/set-getter-0.1.1
build(deps): bump set-getter from 0.1.0 to 0.1.1
2021-07-06 21:08:57 +01:00
dependabot[bot]
6567ad423d
build(deps): bump set-getter from 0.1.0 to 0.1.1
Bumps [set-getter](https://github.com/doowb/set-getter) from 0.1.0 to 0.1.1.
- [Release notes](https://github.com/doowb/set-getter/releases)
- [Commits](https://github.com/doowb/set-getter/commits/0.1.1)

---
updated-dependencies:
- dependency-name: set-getter
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2021-06-21 21:21:01 +00:00
Rodrigo Fernandes
73ab5ba050
Merge pull request #389 from mohd-akram/remove-redundant-classes
Remove redundant HTML classes
2021-06-03 22:34:12 +01:00
Rodrigo Fernandes
be5d5ee1c7
Merge pull request #386 from rtfpessoa/dependabot/npm_and_yarn/postcss-8.2.10
build(deps-dev): [security] bump postcss from 8.2.9 to 8.2.10
2021-06-03 22:21:10 +01:00
Rodrigo Fernandes
110b90bc75
Merge pull request #388 from rtfpessoa/dependabot/npm_and_yarn/browserslist-4.16.6
build(deps): bump browserslist from 4.16.3 to 4.16.6
2021-06-03 22:21:02 +01:00
Rodrigo Fernandes
79d061f431
Merge pull request #390 from rtfpessoa/dependabot/npm_and_yarn/ws-7.4.6
build(deps): bump ws from 7.4.4 to 7.4.6
2021-06-03 22:20:52 +01:00
dependabot[bot]
1882e58796
build(deps): bump ws from 7.4.4 to 7.4.6
Bumps [ws](https://github.com/websockets/ws) from 7.4.4 to 7.4.6.
- [Release notes](https://github.com/websockets/ws/releases)
- [Commits](https://github.com/websockets/ws/compare/7.4.4...7.4.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-29 22:18:46 +00:00
Mohamed Akram
ac9e2ce706 Remove redundant HTML classes 2021-05-29 02:08:47 +04:00
dependabot[bot]
8735dfccb6
build(deps): bump browserslist from 4.16.3 to 4.16.6
Bumps [browserslist](https://github.com/browserslist/browserslist) from 4.16.3 to 4.16.6.
- [Release notes](https://github.com/browserslist/browserslist/releases)
- [Changelog](https://github.com/browserslist/browserslist/blob/main/CHANGELOG.md)
- [Commits](https://github.com/browserslist/browserslist/compare/4.16.3...4.16.6)

Signed-off-by: dependabot[bot] <support@github.com>
2021-05-25 03:41:11 +00:00
dependabot-preview[bot]
ea14e3d5ef
build(deps-dev): [security] bump postcss from 8.2.9 to 8.2.10
Bumps [postcss](https://github.com/postcss/postcss) from 8.2.9 to 8.2.10. **This update includes a security fix.**
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.2.9...8.2.10)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-05-10 15:54:18 +00:00
Rodrigo Fernandes
4f5db83d30
style: Fix format 2021-05-10 12:05:19 +01:00
Rodrigo Fernandes
97b245883c
Merge pull request #384 from domdomegg/update-documentation
docs: Update configuration reference
2021-05-10 12:04:18 +01:00
Rodrigo Fernandes
8c6ed5aa14
clean: Apply suggestions from code review 2021-05-10 11:56:14 +01:00
Adam Jones
78b9cb69ae
docs: Update configuration reference
- Add undocumented srcPrefix and dstPrefix options
- Better specify types and defaults
- Reorder options to match implementation
- Add example for rawTemplates
- Remove invalid 'inputFormat' option from examples
2021-05-10 11:26:35 +01:00
Rodrigo Fernandes
9ed73c7a66 fix: Use correct webpack typings 2021-04-08 14:55:58 +01:00
Rodrigo Fernandes
defff26b9a fix: Setup husky correctly 2021-04-08 13:14:00 +01:00
Rodrigo Fernandes
0475545a01
Merge pull request #363 from rtfpessoa/bump-dependencies
bump: Update dependencies
2021-04-04 13:17:06 +01:00
Rodrigo Fernandes
fb66c8f983
bump: Update dependencies 2021-04-04 13:11:30 +01:00
Rodrigo Fernandes
006d82c02b
clean: Improve README with suggestions 2021-04-04 12:29:44 +01:00
Rodrigo Fernandes
8fc491c499
Merge pull request #378 from charguer/update-readme-with-plain-html-example
Update readme with fully worked-out plain html example
2021-04-04 12:00:18 +01:00
charguer
794bdb2e1c Update readme with fully worked-out plain html example 2021-03-31 16:26:34 +02:00
Rodrigo Fernandes
642b000ad4
Merge pull request #374 from rtfpessoa/dependabot/npm_and_yarn/y18n-4.0.1
build(deps): [security] bump y18n from 4.0.0 to 4.0.1
2021-03-30 22:49:11 +01:00
dependabot-preview[bot]
ba257b53dc
build(deps): [security] bump y18n from 4.0.0 to 4.0.1
Bumps [y18n](https://github.com/yargs/y18n) from 4.0.0 to 4.0.1. **This update includes a security fix.**
- [Release notes](https://github.com/yargs/y18n/releases)
- [Changelog](https://github.com/yargs/y18n/blob/master/CHANGELOG.md)
- [Commits](https://github.com/yargs/y18n/commits)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-03-29 17:21:08 +00:00
Rodrigo Fernandes
084eb408dd
Merge pull request #369 from huggingface/diff-max-line-length
feature: `diffMaxLineLength` to mark file diff as too big depending on diff line length
2021-03-16 09:26:26 +00:00
Pierric Cistac
bf7b52ad30
regroup handling of diffMaxLineLength and diffMaxChanges in parser 2021-03-11 18:17:33 -05:00
Pierric Cistac
a4e619efa4
feature: new diffMaxLineLength
Mark a file diff as too big if diff line length > threshold
2021-03-11 18:10:14 -05:00
Rodrigo Fernandes
51d19ebc2e
Merge pull request #367 from rtfpessoa/dependabot/npm_and_yarn/elliptic-6.5.4
build(deps): [security] bump elliptic from 6.5.3 to 6.5.4
2021-03-08 20:43:10 +00:00
dependabot-preview[bot]
32b7cfc5d1
build(deps): [security] bump elliptic from 6.5.3 to 6.5.4
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.3 to 6.5.4. **This update includes a security fix.**
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.3...v6.5.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2021-03-08 16:27:03 +00:00
Rodrigo Fernandes
38a9d8f93e
Merge pull request #365 from huggingface/diff-max-lines
feature: bypass parsing/rendering of file diff if specific threshold is crossed
2021-03-04 22:41:02 +00:00
Rodrigo Fernandes
e55d145036
Merge pull request #366 from huggingface/fix-viewed-checkbox
fix: only display "Viewed" checkbox if `fileContentToggle` is set
2021-03-04 22:40:24 +00:00
Pierric Cistac
7668889493
fix: only display "Viewed" checkbox if fileContentToggle is set 2021-03-01 17:17:08 -05:00
Pierric Cistac
a65a3b9562
update tests 2021-03-01 16:05:12 -05:00
Pierric Cistac
08f14e2db1
rm package-lock.json 2021-03-01 14:54:03 -05:00
Pierric Cistac
f220ca11e4
move everything inside parser 2021-03-01 14:48:12 -05:00
Pierric Cistac
b057c6f308
fix: URLParams typing in demo with new diffTooBigMessage option 2021-02-25 15:30:09 -05:00
Pierric Cistac
9aa2ea924e
doc: add diffMaxChanges and diffTooBigMessage in readme 2021-02-25 15:30:09 -05:00
Pierric Cistac
5915ecdaa1
feature: display message instead of diff if isTooBig is true
A default `Diff too big to be displayed` message is rendered for any file diff where `isTooBig` is `true`.

A new `diffTooBigMessage` option in render config allows to fully customize the message and receives the file index in the diff as an argument. It can be used to render a link to the raw file diff for example.
2021-02-25 14:08:18 -05:00
Pierric Cistac
ea9c1fee48
feature: new diffMaxChanges in parser config
If `diffMaxChanges` is set in parser config, and its value is exceeded for a given file diff, then parsing for this file is stopped, and `isTooBig` is set to `true` in the `DiffFile`
2021-02-25 14:02:43 -05:00
Rodrigo Fernandes
f046d183df
Merge pull request #360 from xlith/fix/space-in-side-by-side-display
fix: remove unnesesary height property in d2h-files-diff class
2021-02-20 11:48:43 +00:00
Civan Yavuzsen
9e831469a5 fix: remove unnesesary height property in d2h-files-diff class 2021-02-07 03:27:57 +03:00
Rodrigo Fernandes
c3d7df3bc5
Merge pull request #358 from mrfyda/feature/collapse-viewed
feature: Hide viewed files
2021-01-24 00:57:32 +00:00
Rafael Cortês
242fc5ae7b
feature: Add selected state style 2021-01-23 22:32:50 +00:00
Rafael Cortês
49bf898e0e
clean: Refactor font style 2021-01-23 22:18:03 +00:00
Rafael Cortês
8ee76bf44b
clean: Refactor function to toggle file contents 2021-01-23 22:16:25 +00:00
Rafael Cortês
316803df77
feature: Hide viewed files 2021-01-23 15:07:14 +00:00
Rodrigo Fernandes
c178c2e91e
Merge pull request #353 from rtfpessoa/dependabot/npm_and_yarn/node-notifier-8.0.1
build(deps): [security] bump node-notifier from 8.0.0 to 8.0.1
2020-12-22 09:06:25 +00:00
dependabot-preview[bot]
cc9d262086
build(deps): [security] bump node-notifier from 8.0.0 to 8.0.1
Bumps [node-notifier](https://github.com/mikaelbr/node-notifier) from 8.0.0 to 8.0.1. **This update includes a security fix.**
- [Release notes](https://github.com/mikaelbr/node-notifier/releases)
- [Changelog](https://github.com/mikaelbr/node-notifier/blob/v8.0.1/CHANGELOG.md)
- [Commits](https://github.com/mikaelbr/node-notifier/compare/v8.0.0...v8.0.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-21 16:56:56 +00:00
Rodrigo Fernandes
e56b2b0980
Merge pull request #352 from rtfpessoa/dependabot/npm_and_yarn/ini-1.3.7
build(deps): [security] bump ini from 1.3.5 to 1.3.7
2020-12-10 17:40:44 +00:00
dependabot-preview[bot]
73c87c1972
build(deps): [security] bump ini from 1.3.5 to 1.3.7
Bumps [ini](https://github.com/isaacs/ini) from 1.3.5 to 1.3.7. **This update includes a security fix.**
- [Release notes](https://github.com/isaacs/ini/releases)
- [Commits](https://github.com/isaacs/ini/compare/v1.3.5...v1.3.7)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-10 17:34:12 +00:00
Rodrigo Fernandes
640935927e
Merge pull request #351 from rtfpessoa/dependabot/npm_and_yarn/highlight.js-10.4.1
build(deps): [security] bump highlight.js from 10.2.1 to 10.4.1
2020-12-08 17:52:29 +00:00
dependabot-preview[bot]
59474646cb
build(deps): [security] bump highlight.js from 10.2.1 to 10.4.1
Bumps [highlight.js](https://github.com/highlightjs/highlight.js) from 10.2.1 to 10.4.1. **This update includes a security fix.**
- [Release notes](https://github.com/highlightjs/highlight.js/releases)
- [Changelog](https://github.com/highlightjs/highlight.js/blob/master/CHANGES.md)
- [Commits](https://github.com/highlightjs/highlight.js/compare/10.2.1...10.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-12-04 16:56:29 +00:00
Rodrigo Fernandes
1f261e6bbf
Merge pull request #348 from rtfpessoa/only-allow-selection-line-content
fix: Only allow selection line content instead of parent element
2020-10-29 09:46:20 +00:00
Rodrigo Fernandes
33076dc13e
fix: Add review suggestions 2020-10-29 09:01:09 +00:00
Rodrigo Fernandes
2d4c293a27
fix: Only allow selection line content instead of parent element 2020-10-27 20:06:45 +00:00
Rodrigo Fernandes
e48259d990
Merge pull request #341 from rtfpessoa/bump-dependencies
Bump dependencies
2020-10-16 22:31:46 +01:00
Rodrigo Fernandes
98db156d30
bump: Update dependencies 2020-10-16 22:24:06 +01:00
Rodrigo Fernandes
908272a00f
fix: Remove cors proxy 2020-10-16 22:07:04 +01:00
Rodrigo Fernandes
275d09972f
Merge pull request #337 from rtfpessoa/bump-dependencies
bump: Update dependencies
2020-09-05 17:46:02 +01:00
Rodrigo Fernandes
27bfd3c987
bump: Update dependencies 2020-09-04 19:21:39 +01:00
Rodrigo Fernandes
739751a021
Merge pull request #334 from rtfpessoa/bump-dependencies
bump: Update dependencies
2020-08-15 15:20:58 +01:00
Rodrigo Fernandes
426d9ed2a5
bump: Update dependencies 2020-08-15 15:09:15 +01:00
Rodrigo Fernandes
ed506ef091
Merge pull request #332 from rtfpessoa/dependabot/npm_and_yarn/elliptic-6.5.3
build(deps): [security] bump elliptic from 6.5.2 to 6.5.3
2020-07-30 13:06:58 +01:00
dependabot-preview[bot]
235dbb153f
build(deps): [security] bump elliptic from 6.5.2 to 6.5.3
Bumps [elliptic](https://github.com/indutny/elliptic) from 6.5.2 to 6.5.3. **This update includes a security fix.**
- [Release notes](https://github.com/indutny/elliptic/releases)
- [Commits](https://github.com/indutny/elliptic/compare/v6.5.2...v6.5.3)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-07-29 21:10:02 +00:00
Rodrigo Fernandes
4162188f80
Merge pull request #329 from rtfpessoa/fix-escaping-long-lines
fix: Enforce escape for lines that are not highlighted
2020-07-26 14:01:11 +01:00
Rodrigo Fernandes
a61c7cfd43
fix: Enforce escape for lines that are not highlighted 2020-07-26 13:56:26 +01:00
Rodrigo Fernandes
c7c56bca03
Merge pull request #326 from rtfpessoa/dependabot/npm_and_yarn/lodash-4.17.19
build(deps): bump lodash from 4.17.15 to 4.17.19
2020-07-24 12:21:52 +01:00
dependabot[bot]
d410c1ac22
build(deps): bump lodash from 4.17.15 to 4.17.19
Bumps [lodash](https://github.com/lodash/lodash) from 4.17.15 to 4.17.19.
- [Release notes](https://github.com/lodash/lodash/releases)
- [Commits](https://github.com/lodash/lodash/compare/4.17.15...4.17.19)

Signed-off-by: dependabot[bot] <support@github.com>
2020-07-16 23:50:54 +00:00
Rodrigo Fernandes
8462e52b30
Merge pull request #325 from campersau/escape_header
escape diff headers for html
2020-06-30 18:57:29 +01:00
campersau
406be9f02a escape diff headers for html 2020-06-27 20:11:28 +02:00
Rodrigo Fernandes
12bf3068bd
Create codeql-analysis.yml 2020-06-25 10:23:43 +01:00
Rodrigo Fernandes
d2a143ef30
Merge pull request #323 from rtfpessoa/dependabot/npm_and_yarn/websocket-extensions-0.1.4
build(deps): [security] bump websocket-extensions from 0.1.3 to 0.1.4
2020-06-06 19:20:53 +01:00
dependabot-preview[bot]
964387c5b0
build(deps): [security] bump websocket-extensions from 0.1.3 to 0.1.4
Bumps [websocket-extensions](https://github.com/faye/websocket-extensions-node) from 0.1.3 to 0.1.4. **This update includes a security fix.**
- [Release notes](https://github.com/faye/websocket-extensions-node/releases)
- [Changelog](https://github.com/faye/websocket-extensions-node/blob/master/CHANGELOG.md)
- [Commits](https://github.com/faye/websocket-extensions-node/compare/0.1.3...0.1.4)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-06-05 20:04:16 +00:00
Rodrigo Fernandes
d7d08f0c36
Merge pull request #322 from rtfpessoa/update-codacy-coverage
Update codacy coverage and bump dependencies
2020-05-09 13:17:47 +01:00
Rodrigo Fernandes
1844fed147
bump: Update node versions 2020-05-09 13:12:15 +01:00
Rodrigo Fernandes
ae91dcedd0
bump: Update highlight.js 2020-05-09 12:36:23 +01:00
Rodrigo Fernandes
c37321b6fa
bump: Update dependencies 2020-05-09 11:27:49 +01:00
Rodrigo Fernandes
10687999f3
bump: Update codacy coverage reporter 2020-05-09 11:23:14 +01:00
Rodrigo Fernandes
c3a037bc65
Merge pull request #319 from timgates42/bugfix_typo_examples
docs: Fix simple typo, exemples -> examples
2020-04-17 19:45:34 +01:00
Tim Gates
ee43076fca
docs: Fix simple typo, exemples -> examples
There is a small typo in README.md.

Should read `examples` rather than `exemples`.
2020-04-17 07:38:27 +10:00
Rodrigo Fernandes
fd78929a3f
Merge pull request #316 from rtfpessoa/bump-dependencies
bump: Update dependencies specially autolinker
2020-03-14 21:19:09 +00:00
Rodrigo Fernandes
5918662d06
bump: Update dependencies specially autolinker 2020-03-14 21:14:33 +00:00
Rodrigo Fernandes
7a57dc9667
Merge pull request #315 from rtfpessoa/bump-dependencies
bump: Update dependencies specially acorn and minimist
2020-03-14 20:50:48 +00:00
Rodrigo Fernandes
ea5129b888
bump: Update dependencies specially acorn and minimist 2020-03-14 20:43:04 +00:00
Rodrigo Fernandes
3d5ebc7509
Merge pull request #314 from rtfpessoa/dependabot/npm_and_yarn/acorn-6.4.1
build(deps): [security] bump acorn from 6.4.0 to 6.4.1
2020-03-13 23:30:46 +00:00
dependabot-preview[bot]
953a5d64bf
build(deps): [security] bump acorn from 6.4.0 to 6.4.1
Bumps [acorn](https://github.com/acornjs/acorn) from 6.4.0 to 6.4.1. **This update includes a security fix.**
- [Release notes](https://github.com/acornjs/acorn/releases)
- [Commits](https://github.com/acornjs/acorn/compare/6.4.0...6.4.1)

Signed-off-by: dependabot-preview[bot] <support@dependabot.com>
2020-03-13 21:28:58 +00:00
Rodrigo Fernandes
fb778f9fa9
Merge pull request #312 from rtfpessoa/fix-usage-examples
doc: Add jsdelivr cdn examples and fix broken links
2020-03-10 20:41:19 +00:00
Rodrigo Fernandes
45632dd0e4
doc: Add jsdelivr cdn examples and fix broken links 2020-03-10 18:33:10 +00:00
Rodrigo Fernandes
559cdb420b
Merge pull request #311 from rtfpessoa/fix-file-list-toggle
fix: Add missing dot in class query selector
2020-03-10 18:32:20 +00:00
Rodrigo Fernandes
76fb5227af
fix: Add missing dot in class query selector 2020-03-10 18:16:04 +00:00
Rodrigo Fernandes
884b95be07
Merge pull request #307 from rtfpessoa/fix-selection-empty-lines-side
fix: Skip selection of structural lines in side diff
2020-02-09 19:23:33 +00:00
Rodrigo Fernandes
05c774139a
fix: Skip selection of structural lines in side diff 2020-02-09 19:06:44 +00:00
Rodrigo Fernandes
90d37608c8 Merge pull request #306 from rtfpessoa/fix-selection-empty-lines
fix: Allow selection of empty lines
2020-02-09 17:11:47 +00:00
Rodrigo Fernandes
7be6ef0f4d
fix: Allow selection of empty lines 2020-02-09 17:07:22 +00:00
Rodrigo Fernandes
4a3ed66135
Merge pull request #305 from rtfpessoa/fix-side-by-side-linenumber
Fix side by side linenumber
2020-02-09 16:30:26 +00:00
Rodrigo Fernandes
0cc9550fbf
Merge pull request #304 from rtfpessoa/implement-smart-selection-in-css
feature: Implement smart selection in CSS
2020-02-09 16:21:51 +00:00
Rodrigo Fernandes
bdd88f4b90
fix: Add missing padding to side by side line numbers 2020-02-09 16:21:06 +00:00
Rodrigo Fernandes
ee58e2d700
feature: Implement smart selection in CSS 2020-02-09 16:08:58 +00:00
Rodrigo Fernandes
4e28c5c327
fix: Git tag push 2020-02-05 21:27:25 +00:00
61 changed files with 23724 additions and 13242 deletions

View file

@ -52,7 +52,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/8504000?v=4",
"profile": "http://heyitsmattwade.com",
"contributions": [
"bug"
"bug",
"code"
]
},
{
@ -79,7 +80,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/1567423?v=4",
"profile": "https://saino.me/",
"contributions": [
"bug"
"bug",
"code"
]
},
{
@ -97,7 +99,8 @@
"avatar_url": "https://avatars2.githubusercontent.com/u/7767299?v=4",
"profile": "http://wesssel.github.io/",
"contributions": [
"security"
"security",
"code"
]
},
{
@ -115,7 +118,8 @@
"avatar_url": "https://avatars1.githubusercontent.com/u/1446970?v=4",
"profile": "https://github.com/sss0791",
"contributions": [
"bug"
"bug",
"code"
]
},
{
@ -124,7 +128,8 @@
"avatar_url": "https://avatars3.githubusercontent.com/u/4741620?v=4",
"profile": "http://researcher.watson.ibm.com/researcher/view.php?person=us-nickm",
"contributions": [
"bug"
"bug",
"code"
]
},
{
@ -142,7 +147,8 @@
"avatar_url": "https://avatars3.githubusercontent.com/u/8926560?v=4",
"profile": "https://twitter.com/pubkeypubkey",
"contributions": [
"doc"
"doc",
"code"
]
},
{
@ -160,7 +166,9 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/1823771?v=4",
"profile": "https://akr.am",
"contributions": [
"bug"
"bug",
"doc",
"code"
]
},
{
@ -178,7 +186,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/8316?v=4",
"profile": "http://twitter.com/dimasabanin",
"contributions": [
"maintenance"
"maintenance",
"code"
]
},
{
@ -196,7 +205,8 @@
"avatar_url": "https://avatars1.githubusercontent.com/u/2196373?v=4",
"profile": "http://webminer.js.org",
"contributions": [
"bug"
"bug",
"doc"
]
},
{
@ -223,7 +233,6 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/1155220?v=4",
"profile": "https://github.com/escitalopram",
"contributions": [
"bug",
"code"
]
},
@ -245,6 +254,88 @@
"contributions": [
"code"
]
},
{
"login": "apeckham",
"name": "Aaron",
"avatar_url": "https://avatars.githubusercontent.com/u/14110?v=4",
"profile": "https://github.com/apeckham",
"contributions": [
"doc"
]
},
{
"login": "pgrimaud",
"name": "Pierre Grimaud",
"avatar_url": "https://avatars.githubusercontent.com/u/1866496?v=4",
"profile": "https://github.com/pgrimaud",
"contributions": [
"doc"
]
},
{
"login": "domdomegg",
"name": "Adam Jones",
"avatar_url": "https://avatars.githubusercontent.com/u/4953590?v=4",
"profile": "https://domdomegg.github.io/",
"contributions": [
"doc"
]
},
{
"login": "charguer",
"name": "Arthur Charguéraud",
"avatar_url": "https://avatars.githubusercontent.com/u/1830652?v=4",
"profile": "https://github.com/charguer",
"contributions": [
"doc"
]
},
{
"login": "Pierrci",
"name": "Pierric Cistac",
"avatar_url": "https://avatars.githubusercontent.com/u/5020707?v=4",
"profile": "https://twitter.com/pierrci",
"contributions": [
"doc",
"code"
]
},
{
"login": "xlith",
"name": "Civan Yavuzşen",
"avatar_url": "https://avatars.githubusercontent.com/u/510560?v=4",
"profile": "https://github.com/xlith",
"contributions": [
"code"
]
},
{
"login": "timgates42",
"name": "Tim Gates",
"avatar_url": "https://avatars.githubusercontent.com/u/47873678?v=4",
"profile": "https://github.com/timgates42",
"contributions": [
"doc"
]
},
{
"login": "campersau",
"name": "campersau",
"avatar_url": "https://avatars.githubusercontent.com/u/4009570?v=4",
"profile": "https://github.com/campersau",
"contributions": [
"code"
]
},
{
"login": "dependabot-preview[bot]",
"name": "dependabot-preview[bot]",
"avatar_url": "https://avatars.githubusercontent.com/in/2141?v=4",
"profile": "https://github.com/apps/dependabot-preview",
"contributions": [
"code"
]
}
],
"contributorsPerLine": 7

View file

@ -1,214 +0,0 @@
version: 2.1
jobs:
checkout-and-version:
docker:
- image: codacy/git-version
working_directory: ~/workdir
steps:
- checkout
- run:
name: Get next version
command: |
export NEXT_VERSION="$(/bin/git-version --folder=$PWD --release-branch=master)"
echo "Next version is ${NEXT_VERSION}"
echo "${NEXT_VERSION}" > .version
- run:
name: Get next npm tag name
command: |
if [ "${CIRCLE_BRANCH}" = "master" ]; then
export PUBLISH_TAG="latest"
elif [ "${CIRCLE_BRANCH}" = "next" ]; then
export PUBLISH_TAG="next"
else
export PUBLISH_TAG="pr"
fi
echo "Next tag is ${PUBLISH_TAG}"
echo "${PUBLISH_TAG}" > .tag
- persist_to_workspace:
root: ~/workdir
paths:
- '*'
build-common: &common-build
docker:
- image: node
working_directory: ~/workdir
steps:
- attach_workspace:
at: ~/workdir
- restore_cache:
key: yarn-cache-{{ checksum "yarn.lock" }}
- run:
name: Log environment setup
command: |
node -v
yarn -v
- run:
name: Install dependencies
command: yarn
- save_cache:
key: yarn-cache-{{ checksum "yarn.lock" }}
paths:
- /usr/local/share/.cache/yarn
- run: yarn run validate
- store_artifacts:
path: coverage
- store_test_results:
path: coverage
build-latest: &latest-build
docker:
- image: node
working_directory: ~/workdir
steps:
- attach_workspace:
at: ~/workdir
- restore_cache:
key: yarn-cache-{{ checksum "yarn.lock" }}
- run:
name: Log environment setup
command: |
node -v
yarn -v
- run:
name: Install dependencies
command: yarn
- save_cache:
key: yarn-cache-{{ checksum "yarn.lock" }}
paths:
- /usr/local/share/.cache/yarn
- run: yarn run validate
- store_artifacts:
path: coverage
- store_test_results:
path: coverage
- run: yarn run coverage:push
- persist_to_workspace:
root: ~/workdir
paths:
- '*'
build-node-10:
<<: *common-build
docker:
- image: node:10
build-node-11:
<<: *common-build
docker:
- image: node:11
build-node-12:
<<: *common-build
docker:
- image: node:12
build-node-13:
<<: *latest-build
docker:
- image: node:13
publish_library:
docker:
- image: node:13
working_directory: ~/workdir
steps:
- attach_workspace:
at: ~/workdir
- run:
name: Configure Yarn version
command: |
yarn config set version-tag-prefix ""
yarn config set version-git-message "Release version %s"
- run:
name: Configure Git
command: |
git config user.email "circleci@users.noreply.github.com"
git config user.name "CircleCI"
- run:
name: Version package
command: |
# Update version in packages to publish
yarn version --non-interactive --new-version $(cat .version)
git push --tags "https://rtfpessoa:$GPR_AUTH_TOKEN@github.com/rtfpessoa/diff2html"
- run:
name: Setup npm credentials
command: |
rm -f .npmrc
touch .npmrc
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" >> .npmrc
echo "registry=https://registry.npmjs.org/" >> .npmrc
echo "access=public" >> .npmrc
echo "save-exact=true" >> .npmrc
- run:
name: Publish npm package
command: |
# Publish package versions to npmjs.org
yarn publish --tag $(cat .tag) --non-interactive --new-version $(cat .version)
- run:
name: Setup gpr credentials
command: |
rm -f .npmrc
touch .npmrc
echo "//npm.pkg.github.com/:_authToken=${GPR_AUTH_TOKEN}" >> .npmrc
echo "@rtfpessoa:registry=https://npm.pkg.github.com/" >> .npmrc
echo "access=public" >> .npmrc
echo "save-exact=true" >> .npmrc
- run:
name: Publish gpr package
command: |
# HACK: Override npm package name to be able to publish in GitHub
sed -i 's/^ "name":.*/ "name": "@rtfpessoa\/diff2html",/g' package.json
echo "Going to publish version $(cat .version) to GitHub"
yarn publish --tag $(cat .tag) --non-interactive --new-version $(cat .version)
# HACK: Restore npm package name
sed -i 's/^ "name":.*/ "name": "diff2html",/g' package.json
publish_website:
machine:
enabled: true
working_directory: ~/workdir
steps:
- attach_workspace:
at: ~/workdir
- run:
name: Deploy
working_directory: ~/workdir/docs
command: |
aws s3 sync --region eu-west-1 --delete . s3://diff2html.xyz --metadata-directive REPLACE --cache-control max-age=31557600
aws cloudfront create-invalidation --region eu-west-1 --distribution-id $AWS_CF_DISTRIBUTION_ID --paths /index.html /demo.html /sitemap.xml /robots.txt
workflows:
validate-and-publish:
jobs:
- checkout-and-version
- build-node-10:
requires:
- checkout-and-version
- build-node-11:
requires:
- checkout-and-version
- build-node-12:
requires:
- checkout-and-version
- build-node-13:
requires:
- checkout-and-version
- publish_approval:
type: approval
requires:
- build-node-10
- build-node-11
- build-node-12
- build-node-13
- publish_library:
requires:
- publish_approval
- publish_website:
requires:
- publish_approval
filters:
branches:
only:
- master

View file

@ -1,58 +0,0 @@
module.exports = {
parser: '@typescript-eslint/parser',
parserOptions: {
ecmaVersion: 2018,
sourceType: 'module',
},
env: {
browser: true,
es6: true,
node: true,
},
globals: {
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
document: 'readonly',
navigator: 'readonly',
window: 'readonly',
},
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/eslint-recommended',
'plugin:@typescript-eslint/recommended',
'plugin:json/recommended',
'plugin:promise/recommended',
'plugin:import/errors',
'plugin:import/warnings',
'plugin:import/typescript',
'plugin:node/recommended',
'plugin:sonarjs/recommended',
'plugin:jest/recommended',
'plugin:jest/style',
'prettier',
'prettier/@typescript-eslint',
'prettier/babel',
],
plugins: ['@typescript-eslint', 'json', 'promise', 'import', 'node', 'sonarjs', 'jest', 'optimize-regex'],
rules: {
// Enable
'optimize-regex/optimize-regex': 'error',
// Hack: For some reason we need pass again the extensions
'node/no-missing-import': [
'error',
{
tryExtensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
},
],
// Disable
// https://github.com/benmosher/eslint-plugin-import/issues/1446
'import/named': 'off',
// We don't need this since we are using transpilation
'node/no-unsupported-features/es-syntax': 'off',
'no-process-exit': 'off',
// Too verbose
'sonarjs/no-duplicate-string': 'off',
// Too verbose
'sonarjs/cognitive-complexity': 'off',
},
};

12
.github/workflows/ci.yml vendored Normal file
View file

@ -0,0 +1,12 @@
name: ci
on:
pull_request:
branches: [master]
jobs:
test-and-publish:
uses: ./.github/workflows/test-and-publish.yml
with:
environment: dev
secrets: inherit

35
.github/workflows/release.yml vendored Normal file
View file

@ -0,0 +1,35 @@
name: release
on:
push:
branches: [master]
jobs:
test-and-publish:
uses: ./.github/workflows/test-and-publish.yml
with:
environment: production
secrets: inherit
publish-website:
runs-on: ubuntu-latest
container:
image: amazon/aws-cli
needs: [test-and-publish]
environment: 'production'
steps:
- name: Download docs
uses: actions/download-artifact@v4
with:
name: docs
path: docs/
- name: Publish to S3
working-directory: docs
env:
AWS_CF_DISTRIBUTION_ID: ${{ secrets.AWS_CF_DISTRIBUTION_ID }}
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
AWS_DEFAULT_REGION: ${{ secrets.AWS_DEFAULT_REGION }}
run: |
aws s3 sync --region eu-west-1 --delete . s3://diff2html.xyz --metadata-directive REPLACE --cache-control max-age=31557600
aws cloudfront create-invalidation --region eu-west-1 --distribution-id $AWS_CF_DISTRIBUTION_ID --paths /index.html /demo.html /sitemap.xml /robots.txt

148
.github/workflows/test-and-publish.yml vendored Normal file
View file

@ -0,0 +1,148 @@
name: test-and-publish
on:
workflow_call:
inputs:
environment:
required: true
type: string
jobs:
version:
runs-on: ubuntu-latest
container:
image: codacy/git-version
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Fix tar access
run: apk add --update --no-progress tar
- name: Fix git access
run: |
git config --global --add safe.directory /__w/diff2html/diff2html
- name: Get next version
run: |
export NEXT_VERSION="$(/bin/git-version --folder=$PWD --release-branch=master)"
echo "Next version is ${NEXT_VERSION}"
echo "${NEXT_VERSION}" > next-version.txt
echo "version=${NEXT_VERSION}" >> $GITHUB_ENV
- name: Get next npm tag name
run: |
if [ "${GITHUB_REF_NAME}" = "master" ]; then
export PUBLISH_TAG="latest"
elif [ "${GITHUB_REF_NAME}" = "next" ]; then
export PUBLISH_TAG="next"
else
export PUBLISH_TAG="pr"
fi
echo "Next tag is ${PUBLISH_TAG}"
echo "${PUBLISH_TAG}" > publish-tag.txt
- name: Upload versions
uses: actions/upload-artifact@v4
with:
name: versions
if-no-files-found: error
path: |
next-version.txt
publish-tag.txt
build:
runs-on: ubuntu-latest
needs: [version]
strategy:
matrix:
node-version: [16.x, 18.x, 20.x, 22.x]
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Use Node.js ${{ matrix.node-version }}
uses: actions/setup-node@v3
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- name: Log environment setup
run: |
node -v
npm -v
- name: Install dependencies
run: npm install
- name: Build templates
run: npm run build:templates
- name: Build library
run: npm run build
publish:
runs-on: ubuntu-latest
needs: [build]
environment: ${{ inputs.environment }}
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Download versions
uses: actions/download-artifact@v4
with:
name: versions
- name: Store version
run: echo "version=$(cat next-version.txt)" >> $GITHUB_ENV
- name: Configure Git
run: |
git config user.email "gh-actions@users.noreply.github.com"
git config user.name "GitHub Actions"
- name: Tag commit
uses: tvdias/github-tagger@v0.0.1
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
tag: '${{ env.version }}'
- name: Install dependencies
run: npm install
- uses: actions/setup-node@v3
with:
registry-url: 'https://registry.npmjs.org'
node-version: '22.x'
- name: Configure NPM version
env:
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
run: |
rm -f .npmrc
touch .npmrc
echo "//registry.npmjs.org/:_authToken=${NODE_AUTH_TOKEN}" >> .npmrc
echo "registry=https://registry.npmjs.org/" >> .npmrc
echo "access=public" >> .npmrc
echo "save-exact=true" >> .npmrc
- name: Version package
run: |
# Update version in packages to publish
npm version $(cat next-version.txt) -m "Release version %s"
- name: Publish to NPM
run: npm publish --tag $(cat publish-tag.txt)
- uses: actions/setup-node@v3
with:
node-version: '22.x'
registry-url: 'https://npm.pkg.github.com'
- name: Configure NPM version
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
run: |
rm -f .npmrc
touch .npmrc
echo "//npm.pkg.github.com/:_authToken=${NODE_AUTH_TOKEN}" >> .npmrc
echo "@rtfpessoa:registry=https://npm.pkg.github.com/" >> .npmrc
echo "access=public" >> .npmrc
echo "save-exact=true" >> .npmrc
- name: Publish to GPR
run: |
# HACK: Override npm package name to be able to publish in GitHub
sed -i 's/^ "name":.*/ "name": "@rtfpessoa\/diff2html",/g' package.json
echo "Going to publish version $(cat next-version.txt) to GitHub"
npm publish --tag $(cat publish-tag.txt)
# HACK: Restore npm package name
sed -i 's/^ "name":.*/ "name": "diff2html",/g' package.json
- name: Upload docs
uses: actions/upload-artifact@v4
with:
name: docs
if-no-files-found: error
path: docs/

11
.gitignore vendored
View file

@ -29,9 +29,18 @@ bower_components/
# Terraform
/terraform/.terraform
/_target/
# Compiled templates
/src/diff2html-templates.*
# Compiled website
/docs/
# Bundles temporary typescript files compiled by webpack
/bundles-out/
# Web bundles
/bundles/
# CommonJS library
/lib/
# ESNext library
/lib-esm/

1
.husky/.gitignore vendored Normal file
View file

@ -0,0 +1 @@
_

3
.husky/pre-commit Executable file
View file

@ -0,0 +1,3 @@
#!/bin/sh
npm run lint:staged

View file

@ -3,7 +3,6 @@
"bracketSpacing": true,
"htmlWhitespaceSensitivity": "css",
"insertPragma": false,
"jsxBracketSameLine": false,
"jsxSingleQuote": false,
"printWidth": 120,
"proseWrap": "always",

View file

@ -10,9 +10,9 @@
- Before sending a pull request make sure your code is tested.
- Before sending a pull request for a feature, be sure to run tests with `yarn test`.
- Before sending a pull request for a feature, be sure to run tests with `npm run test`.
- Use the same coding style as the rest of the codebase, most of the check can be performed with `yarn run lint`.
- Use the same coding style as the rest of the codebase, most of the check can be performed with `npm run run lint`.
- Use `git rebase` (not `git merge`) to sync your work from time to time with the master branch.

635
README.md
View file

@ -1,23 +1,20 @@
# diff2html
[![Codacy Quality Badge](https://api.codacy.com/project/badge/Grade/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Grade)
[![Codacy Coverage Badge](https://api.codacy.com/project/badge/Coverage/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Coverage)
[![CircleCI](https://circleci.com/gh/rtfpessoa/diff2html.svg?style=svg)](https://circleci.com/gh/rtfpessoa/diff2html)
[![npm](https://img.shields.io/npm/v/diff2html)](https://www.npmjs.com/package/diff2html)
[![node](https://img.shields.io/node/v/diff2html)](https://www.npmjs.com/package/diff2html)
[![npm](https://img.shields.io/npm/l/diff2html)](https://www.npmjs.com/package/diff2html)
[![GitHub Actions](https://github.com/rtfpessoa/diff2html/actions/workflows/release.yml/badge.svg)](https://github.com/rtfpessoa/diff2html/actions/workflows/release.yml)
[![npm](https://img.shields.io/npm/v/diff2html.svg)](https://www.npmjs.com/package/diff2html)
[![Dependency Status](https://david-dm.org/rtfpessoa/diff2html.svg)](https://david-dm.org/rtfpessoa/diff2html)
[![devDependency Status](https://david-dm.org/rtfpessoa/diff2html/dev-status.svg)](https://david-dm.org/rtfpessoa/diff2html#info=devDependencies)
[![cdnjs](https://img.shields.io/cdnjs/v/diff2html)](https://cdnjs.com/libraries/diff2html)
[![npm weekly downloads](https://img.shields.io/npm/dw/diff2html)](https://www.npmjs.com/package/diff2html)
[![npm monthly downloads](https://img.shields.io/npm/dm/diff2html)](https://www.npmjs.com/package/diff2html)
[![npm yearly downloads](https://img.shields.io/npm/dy/diff2html)](https://www.npmjs.com/package/diff2html)
[![npm downloads](https://img.shields.io/npm/dt/diff2html)](https://www.npmjs.com/package/diff2html)
[![node](https://img.shields.io/node/v/diff2html.svg)]() [![npm](https://img.shields.io/npm/l/diff2html.svg)]()
[![npm](https://img.shields.io/npm/dm/diff2html.svg)](https://www.npmjs.com/package/diff2html)
[![All Contributors](https://img.shields.io/badge/all_contributors-22-orange.svg?style=flat-square)](#contributors)
[![Gitter](https://badges.gitter.im/rtfpessoa/diff2html.svg)](https://gitter.im/rtfpessoa/diff2html?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
[![jsdelivr CDN Downloads](https://data.jsdelivr.com/v1/package/npm/diff2html/badge)](https://www.jsdelivr.com/package/npm/diff2html)
[![All Contributors](https://img.shields.io/badge/all_contributors-22-orange)](#contributors)
diff2html generates pretty HTML diffs from git diff or unified diff output.
[![NPM](https://nodei.co/npm/diff2html.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/diff2html/)
## Table of Contents
<!-- toc -->
@ -26,16 +23,18 @@ diff2html generates pretty HTML diffs from git diff or unified diff output.
- [Online Example](#online-example)
- [Distributions](#distributions)
- [Usage](#usage)
- [Diff Text Input](#diff-text-input)
- [Diff2HtmlUI Usage](#diff2htmlui-usage)
- [Diff2HtmlUI API](#diff2htmlui-api)
- [Diff2HtmlUI Configuration](#diff2htmlui-configuration)
- [Diff2HtmlUI Browser](#diff2htmlui-browser)
- [Diff2HtmlUI Examples](#diff2htmlui-examples)
- [Diff2Html Usage](#diff2html-usage)
- [Diff2Html API](#diff2html-api)
- [Diff2Html Configuration](#diff2html-configuration)
- [Diff2Html Browser](#diff2html-browser)
- [Diff2Html NPM / Node.js Library](#diff2html-npm--nodejs-library)
- [Diff2Html Examples](#diff2html-examples)
- [Diff2HtmlUI Usage](#diff2htmlui-usage)
- [Diff2HtmlUI API](#diff2htmlui-api)
- [Diff2HtmlUI Configuration](#diff2htmlui-configuration)
- [Diff2HtmlUI Browser](#diff2htmlui-browser)
- [Troubleshooting](#troubleshooting)
- [1. Out of memory or Slow execution](#1-out-of-memory-or-slow-execution)
- [Contribute](#contribute)
@ -65,218 +64,64 @@ diff2html generates pretty HTML diffs from git diff or unified diff output.
## Online Example
> Go to [diff2html](https://diff2html.xyz/)
> Go to [diff2html](https://diff2html.xyz/demo.html)
## Distributions
- [jsdelivr CDN](https://www.jsdelivr.com/package/npm/diff2html)
- [WebJar](http://www.webjars.org/)
- [Node Library](https://www.npmjs.org/package/diff2html)
- [NPM CLI](https://www.npmjs.org/package/diff2html-cli)
- Manually download and import:
- Manually use from jsdelivr or build the project:
- Browser / Bundle
- Parser and HTML Generator
- [bundles/js/diff2html.min.js](./bundles/js/diff2html.min.js) - includes the diff parser and html generator
- [bundles/js/diff2html.min.js](https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html.min.js) - includes the
diff parser and html generator
- Wrapper and helper adding syntax highlight, synchronized scroll, and other nice features
- [bundles/js/diff2html-ui.min.js](./bundles/js/diff2html-ui.min.js) - includes the wrapper of diff2html with
highlight for all `highlight.js` supported languages
- [bundles/js/diff2html-ui-slim.min.js](./bundles/js/diff2html-ui-slim.min.js) - includes the wrapper of diff2html
with "the most common" `highlight.js` supported languages
- [bundles/js/diff2html-ui-base.min.js](./bundles/js/diff2html-ui-base.min.js) - includes the wrapper of diff2html
without including a `highlight.js` implementation. You can use it without syntax highlight or by passing your
own implementation with the languages you prefer
- [bundles/js/diff2html-ui.min.js](https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js) -
includes the wrapper of diff2html with highlight for all `highlight.js` supported languages
- [bundles/js/diff2html-ui-slim.min.js](https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui-slim.min.js) -
includes the wrapper of diff2html with "the most common" `highlight.js` supported languages
- [bundles/js/diff2html-ui-base.min.js](https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui-base.min.js) -
includes the wrapper of diff2html without including a `highlight.js` implementation. You can use it without
syntax highlight or by passing your own implementation with the languages you prefer
- NPM / Node.js library
- ES5
- [lib/diff2html.js](./lib/diff2html.js) - includes the diff parser and html generator
- [lib/ui/js/diff2html-ui.js](./lib/ui/js/diff2html-ui.js) - includes the wrapper of diff2html with highlight for
all `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-slim.js](./lib/ui/js/diff2html-ui-slim.js) - includes the wrapper of diff2html with "the
most common" `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-base.js](./lib/ui/js/diff2html-ui-base.js)
- [lib/diff2html.js](https://cdn.jsdelivr.net/npm/diff2html/lib/diff2html.js) - includes the diff parser and html
generator
- [lib/ui/js/diff2html-ui.js](https://cdn.jsdelivr.net/npm/diff2html/lib/ui/js/diff2html-ui.js) - includes the
wrapper of diff2html with highlight for all `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-slim.js](https://cdn.jsdelivr.net/npm/diff2html/lib/ui/js/diff2html-ui-slim.js) -
includes the wrapper of diff2html with "the most common" `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-base.js](https://cdn.jsdelivr.net/npm/diff2html/lib/ui/js/diff2html-ui-base.js)
- ES6
- [lib-esm/diff2html.js](./lib-esm/diff2html.js) - includes the diff parser and html generator
- [lib/ui/js/diff2html-ui.js](./lib/ui/js/diff2html-ui.js) - includes the wrapper of diff2html with highlight for
all `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-slim.js](./lib/ui/js/diff2html-ui-slim.js) - includes the wrapper of diff2html with "the
most common" `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-base.js](./lib/ui/js/diff2html-ui-base.js) - includes the wrapper of diff2html without
including a `highlight.js` implementation. You can use it without syntax highlight or by passing your own
implementation with the languages you prefer
- [lib-esm/diff2html.js](https://cdn.jsdelivr.net/npm/diff2html/lib-esm/diff2html.js) - includes the diff parser
and html generator
- [lib/ui/js/diff2html-ui.js](https://cdn.jsdelivr.net/npm/diff2html/lib/ui/js/diff2html-ui.js) - includes the
wrapper of diff2html with highlight for all `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-slim.js](https://cdn.jsdelivr.net/npm/diff2html/lib/ui/js/diff2html-ui-slim.js) -
includes the wrapper of diff2html with "the most common" `highlight.js` supported languages
- [lib/ui/js/diff2html-ui-base.js](https://cdn.jsdelivr.net/npm/diff2html/lib/ui/js/diff2html-ui-base.js) -
includes the wrapper of diff2html without including a `highlight.js` implementation. You can use it without
syntax highlight or by passing your own implementation with the languages you prefer
## Usage
Diff2Html can be used in various ways as listed in the [distributions](#distributions) section. The two main ways are:
- [Diff2Html](#diff2html-usage): using the parser and html generator directly from the library gives you complete
control about what you can do with the json or html generated.
- [Diff2HtmlUI](#diff2htmlui-usage): using this wrapper makes it easy to inject the html in the DOM and adds some nice
features to the diff, like syntax highlight.
- [Diff2Html](#diff2html-usage): using the parser and html generator directly from the library gives you complete
control about what you can do with the json or html generated.
Bellow you can find more details and exemples about each option.
Below you can find more details and examples about each option.
## Diff2Html Usage
## Diff Text Input
To load correctly in the Browser you always need to include the stylesheet in the final HTML.
Import the stylesheet
```html
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="bundles/css/diff2html.min.css" />
```
You can also refer to it from a CDN like [CDNJS](https://cdnjs.com/libraries/diff2html).
### Diff2Html API
> JSON representation of the diff
```ts
function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): DiffFile[];
```
> Pretty HTML representation of the diff
```ts
function html(diffInput: string | DiffFile[], configuration: Diff2HtmlConfig = {}): string;
```
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
### Diff2Html Configuration
The HTML output accepts a Javascript object with configuration. Possible options:
- `outputFormat`: the format of the output data: `'line-by-line'` or `'side-by-side'`, default is `'line-by-line'`
- `drawFileList`: show a file list before the diff: `true` or `false`, default is `true`
- `diffStyle`: show differences level in each line: `word` or `char`, default is `word`
- `matching`: matching level: `'lines'` for matching lines, `'words'` for matching lines and words or `'none'`, default
is `none`
- `matchWordsThreshold`: similarity threshold for word matching, default is `0.25`
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is
`2500`
- `maxLineSizeInBlockForComparison`: maximum number os characters of the bigger line in a block to apply comparison,
default is `200`
- `maxLineLengthHighlight`: only perform diff changes highlight if lines are smaller than this, default is `10000`
- `renderNothingWhenEmpty`: render nothing if the diff shows no change in its comparison: `true` or `false`, default is
`false`
- `compiledTemplates`: object with previously compiled templates to replace parts of the html
- `rawTemplates`: object with raw not compiled templates to replace parts of the html
> For more information regarding the possible templates look into
> [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
### Diff2Html Browser
Import the stylesheet and the library code
```html
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="bundles/css/diff2html.min.css" />
<!-- Javascripts -->
<script type="text/javascript" src="bundles/js/diff2html.min.js"></script>
```
It will now be available as a global variable named `Diff2Html`.
```js
document.addEventListener('DOMContentLoaded', () => {
var diffHtml = global.Diff2Html.html('<Unified Diff String>', {
drawFileList: true,
matching: 'lines',
outputFormat: 'side-by-side',
});
document.getElementById('destination-elem-id').innerHTML = diffHtml;
});
```
### Diff2Html NPM / Node.js Library
```js
const Diff2html = require('diff2html');
const diffJson = Diff2html.parse('<Unified Diff String>');
const diffHtml = Diff2html.html(diffJson, { drawFileList: true });
document.getElementById('destination-elem-id').innerHTML = diffHtml;
```
### Diff2Html Examples
#### Diff2Html Angular Example
- Typescript
```typescript
import * as Diff2Html from 'diff2html';
import { Component, OnInit } from '@angular/core';
export class AppDiffComponent implements OnInit {
outputHtml: string;
constructor() {
this.init();
}
ngOnInit() {}
init() {
let strInput =
'--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n';
let outputHtml = Diff2Html.html(strInput, { drawFileList: true, matching: 'lines' });
this.outputHtml = outputHtml;
}
}
```
- HTML
```html
<!DOCTYPE html>
<html>
<head>
<title>diff2html</title>
</head>
<body>
<div [innerHtml]="outputHtml"></div>
</body>
</html>
```
- `.angular-cli.json` - Add styles
```json
"styles": [
"diff2html.min.css"
]
```
#### Diff2Html Vue.js Example
```vue
<template>
<div v-html="prettyHtml" />
</template>
<script>
import * as Diff2Html from 'diff2html';
import 'diff2html/bundles/css/diff2html.min.css';
export default {
data() {
return {
diffs:
'--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n',
};
},
computed: {
prettyHtml() {
return Diff2Html.html(this.diffs, {
drawFileList: true,
matching: 'lines',
outputFormat: 'side-by-side',
});
},
},
};
</script>
```
diff2html accepts the text contents of a
[unified diff](https://www.gnu.org/software/diffutils/manual/html_node/Unified-Format.html) or the superset format git
diff (https://git-scm.com/docs/git-diff) (not combined or word diff). To provide multiples files as input just
concatenate the diffs (just like the output of git diff).
## Diff2HtmlUI Usage
@ -308,21 +153,18 @@ draw(): void
synchronisedScroll(): void
fileListToggle(startVisible: boolean): void
highlightCode(): void
smartSelection(): void
stickyFileHeaders(): void
```
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
### Diff2HtmlUI Configuration
- `synchronisedScroll`: scroll both panes in side-by-side mode: `true` or `false`, default is `true`
- `highlight`: syntax highlight the code on the diff: `true` or `false`, default is `true`
- `fileListToggle`: allow the file summary list to be toggled: `true` or `false`, default is `true`
- `fileListStartVisible`: choose if the file summary list starts visible: `true` or `false`, default is `false`
- `smartSelection`: allow selection of the code without including line numbers of line prefixes: `true` or `false`,
default is `true`
> NOTE: All the options from Diff2Html are also valid configurations in Diff2HtmlUI
- `fileContentToggle`: allow each file contents to be toggled: `true` or `false`, default is `true`
- `stickyFileHeaders`: make file headers sticky: `true` or `false`, default is `true`
- [All the options](#diff2html-configuration) from Diff2Html are also valid configurations in Diff2HtmlUI
### Diff2HtmlUI Browser
@ -330,10 +172,10 @@ smartSelection(): void
```html
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="bundles/css/diff2html.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
<!-- Javascripts -->
<script type="text/javascript" src="bundles/js/diff2html-ui.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
```
#### Init
@ -355,13 +197,15 @@ diff2htmlUi.draw();
#### Syntax Highlight
**NOTE:** The highlight.js css should come before the diff2html css
```html
<!-- Stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.min.css" />
<link rel="stylesheet" type="text/css" href="bundles/css/diff2html.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
<!-- Javascripts -->
<script type="text/javascript" src="bundles/js/diff2html-ui.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
```
> Pass the option `highlight` with value true or invoke `diff2htmlUi.highlightCode()` after `diff2htmlUi.draw()`.
@ -369,27 +213,42 @@ diff2htmlUi.draw();
```js
document.addEventListener('DOMContentLoaded', () => {
const diffString = `diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;
const targetElement = document.getElementById('myDiffElement');
const configuration = { inputFormat: 'json', drawFileList: true, matching: 'lines', highlight: true };
const configuration = { drawFileList: true, matching: 'lines', highlight: true };
const diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
diff2htmlUi.draw();
diff2htmlUi.highlightCode();
});
```
When using the `auto` color scheme, you will need to specify both the light and dark themes for highlight.js to use.
```html
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css"
media="screen and (prefers-color-scheme: light)"
/>
<link
rel="stylesheet"
href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github-dark.min.css"
media="screen and (prefers-color-scheme: dark)"
/>
```
#### Collapsable File Summary List
> Add the dependencies.
```html
<!-- Javascripts -->
<script type="text/javascript" src="bundles/js/diff2html-ui.min.js"></script>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
```
> Invoke the Diff2HtmlUI helper Pass the option `fileListToggle` with value true or invoke
@ -404,6 +263,263 @@ document.addEventListener('DOMContentLoaded', () => {
});
```
### Diff2HtmlUI Examples
#### Example with plain HTML+CSS+JS
```html
<!doctype html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
<!-- Make sure to load the highlight.js CSS file before the Diff2Html CSS file -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/10.7.1/styles/github.min.css" />
<link
rel="stylesheet"
type="text/css"
href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css"
/>
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html-ui.min.js"></script>
</head>
<script>
const diffString = `diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;
document.addEventListener('DOMContentLoaded', function () {
var targetElement = document.getElementById('myDiffElement');
var configuration = {
drawFileList: true,
fileListToggle: false,
fileListStartVisible: false,
fileContentToggle: false,
matching: 'lines',
outputFormat: 'side-by-side',
synchronisedScroll: true,
highlight: true,
renderNothingWhenEmpty: false,
};
var diff2htmlUi = new Diff2HtmlUI(targetElement, diffString, configuration);
diff2htmlUi.draw();
diff2htmlUi.highlightCode();
});
</script>
<body>
<div id="myDiffElement"></div>
</body>
</html>
```
#### StimulusJS with TypeScript
```ts
import { Controller } from '@hotwired/stimulus';
import { Diff2HtmlUI, Diff2HtmlUIConfig } from 'diff2html/lib/ui/js/diff2html-ui-slim.js';
// Requires `npm install highlight.js`
import 'highlight.js/styles/github.css';
import 'diff2html/bundles/css/diff2html.min.css';
export default class extends Controller {
connect(): void {
const diff2htmlUi = new Diff2HtmlUI(this.diffElement, this.unifiedDiff, this.diffConfiguration);
diff2htmlUi.draw();
}
get unifiedDiff(): string {
return this.data.get('unifiedDiff') || '';
}
get diffElement(): HTMLElement {
return this.element as HTMLElement;
}
get diffConfiguration(): Diff2HtmlUIConfig {
return {
drawFileList: true,
matching: 'lines',
};
}
}
```
## Diff2Html Usage
### Diff2Html API
> JSON representation of the diff
```ts
function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): DiffFile[];
```
> Pretty HTML representation of the diff
```ts
function html(diffInput: string | DiffFile[], configuration: Diff2HtmlConfig = {}): string;
```
### Diff2Html Configuration
The HTML output accepts a Javascript object with configuration. Possible options:
- `outputFormat`: the format of the output data: `'line-by-line'` or `'side-by-side'`, default is `'line-by-line'`
- `drawFileList`: show a file list before the diff: `true` or `false`, default is `true`
- `srcPrefix`: add a prefix to all source (before changes) filepaths, default is `''`. Should match the prefix used when
[generating the diff](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---src-prefixltprefixgt).
- `dstPrefix`: add a prefix to all destination (after changes) filepaths, default is `''`. Should match the prefix used
when [generating the diff](https://git-scm.com/docs/git-diff#Documentation/git-diff.txt---dst-prefixltprefixgt)
- `diffMaxChanges`: number of changed lines after which a file diff is deemed as too big and not displayed, default is
`undefined`
- `diffMaxLineLength`: number of characters in a diff line after which a file diff is deemed as too big and not
displayed, default is `undefined`
- `diffTooBigMessage`: function allowing to customize the message in case of file diff too big (if `diffMaxChanges` or
`diffMaxLineLength` is set). Will be given a file index as a number and should return a string.
- `matching`: matching level: `'lines'` for matching lines, `'words'` for matching lines and words or `'none'`, default
is `none`
- `matchWordsThreshold`: similarity threshold for word matching, default is `0.25`
- `maxLineLengthHighlight`: only perform diff changes highlight if lines are smaller than this, default is `10000`
- `diffStyle`: show differences level in each line: `'word'` or `'char'`, default is `'word'`
- `renderNothingWhenEmpty`: render nothing if the diff shows no change in its comparison: `true` or `false`, default is
`false`
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is
`2500`
- `maxLineSizeInBlockForComparison`: maximum number of characters of the bigger line in a block to apply comparison,
default is `200`
- `compiledTemplates`: object ([Hogan.js](https://github.com/twitter/hogan.js/) template values) with previously
compiled templates to replace parts of the html, default is `{}`. For example:
`{ "tag-file-changed": Hogan.compile("<span class="d2h-tag d2h-changed d2h-changed-tag">MODIFIED</span>") }`
- `rawTemplates`: object (string values) with raw not compiled templates to replace parts of the html, default is `{}`.
For example: `{ "tag-file-changed": "<span class="d2h-tag d2h-changed d2h-changed-tag">MODIFIED</span>" }`
> For more information regarding the possible templates look into
> [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
- `highlightLanguages`: Map of extension to language name, used for highlighting. This overrides the default language
detection based on file extensions.
- `colorScheme`: color scheme to use for the diff, default is `light`. Possible values are `light`, `dark`, and `auto`
which will use the browser's preferred color scheme.
### Diff2Html Browser
Import the stylesheet and the library code.
To load correctly in the Browser you need to include the stylesheet in the final HTML.
```html
<!-- CSS -->
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
<!-- Javascripts -->
<script type="text/javascript" src="https://cdn.jsdelivr.net/npm/diff2html/bundles/js/diff2html.min.js"></script>
```
It will now be available as a global variable named `Diff2Html`.
```js
document.addEventListener('DOMContentLoaded', () => {
var diffHtml = Diff2Html.html('<Unified Diff String>', {
drawFileList: true,
matching: 'lines',
outputFormat: 'side-by-side',
});
document.getElementById('destination-elem-id').innerHTML = diffHtml;
});
```
### Diff2Html NPM / Node.js Library
```js
const Diff2html = require('diff2html');
const diffJson = Diff2html.parse('<Unified Diff String>');
const diffHtml = Diff2html.html(diffJson, { drawFileList: true });
console.log(diffHtml);
```
### Diff2Html Examples
#### Example with Angular
- Typescript
```typescript
import * as Diff2Html from 'diff2html';
import { Component, OnInit } from '@angular/core';
export class AppDiffComponent implements OnInit {
outputHtml: string;
constructor() {
this.init();
}
ngOnInit() {}
init() {
let strInput =
'--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n';
let outputHtml = Diff2Html.html(strInput, { drawFileList: true, matching: 'lines' });
this.outputHtml = outputHtml;
}
}
```
- HTML
```html
<!doctype html>
<html>
<head>
<title>diff2html</title>
</head>
<body>
<div [innerHtml]="outputHtml"></div>
</body>
</html>
```
- `.angular-cli.json` - Add styles
```json
"styles": [
"diff2html.min.css"
]
```
#### Example with Vue.js
```vue
<template>
<div v-html="prettyHtml" />
</template>
<script>
import * as Diff2Html from 'diff2html';
import 'diff2html/bundles/css/diff2html.min.css';
export default {
data() {
return {
diffs:
'--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n',
};
},
computed: {
prettyHtml() {
return Diff2Html.html(this.diffs, {
drawFileList: true,
matching: 'lines',
outputFormat: 'side-by-side',
});
},
},
};
</script>
```
## Troubleshooting
### 1. Out of memory or Slow execution
@ -431,42 +547,53 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://rtfpessoa.xyz"><img src="https://avatars0.githubusercontent.com/u/902384?v=4" width="100px;" alt=""/><br /><sub><b>Rodrigo Fernandes</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=rtfpessoa" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/stockmind"><img src="https://avatars3.githubusercontent.com/u/5653847?v=4" width="100px;" alt=""/><br /><sub><b>stockmind</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=stockmind" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/lantian"><img src="https://avatars3.githubusercontent.com/u/535545?v=4" width="100px;" alt=""/><br /><sub><b>Ivan Vorontsov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=lantian" title="Code">💻</a></td>
<td align="center"><a href="http://www.nick-brewer.com"><img src="https://avatars1.githubusercontent.com/u/129300?v=4" width="100px;" alt=""/><br /><sub><b>Nick Brewer</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=brewern" title="Code">💻</a></td>
<td align="center"><a href="http://heyitsmattwade.com"><img src="https://avatars0.githubusercontent.com/u/8504000?v=4" width="100px;" alt=""/><br /><sub><b>Matt Wade</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Aromellem" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://mrfyda.github.io"><img src="https://avatars1.githubusercontent.com/u/593860?v=4" width="100px;" alt=""/><br /><sub><b>Rafael Cortês</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=mrfyda" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nmatpt"><img src="https://avatars2.githubusercontent.com/u/5034733?v=4" width="100px;" alt=""/><br /><sub><b>Nuno Teixeira</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=nmatpt" title="Code">💻</a></td>
<td align="center"><a href="https://rtfpessoa.xyz"><img src="https://avatars0.githubusercontent.com/u/902384?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rodrigo Fernandes</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=rtfpessoa" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/stockmind"><img src="https://avatars3.githubusercontent.com/u/5653847?v=4?s=100" width="100px;" alt=""/><br /><sub><b>stockmind</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=stockmind" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/lantian"><img src="https://avatars3.githubusercontent.com/u/535545?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ivan Vorontsov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=lantian" title="Code">💻</a></td>
<td align="center"><a href="http://www.nick-brewer.com"><img src="https://avatars1.githubusercontent.com/u/129300?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nick Brewer</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=brewern" title="Code">💻</a></td>
<td align="center"><a href="http://heyitsmattwade.com"><img src="https://avatars0.githubusercontent.com/u/8504000?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Wade</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Aromellem" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=romellem" title="Code">💻</a></td>
<td align="center"><a href="http://mrfyda.github.io"><img src="https://avatars1.githubusercontent.com/u/593860?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rafael Cortês</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=mrfyda" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nmatpt"><img src="https://avatars2.githubusercontent.com/u/5034733?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nuno Teixeira</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=nmatpt" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://saino.me/"><img src="https://avatars0.githubusercontent.com/u/1567423?v=4" width="100px;" alt=""/><br /><sub><b>Koki Oyatsu</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Akaishuu0123" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://www.jamesmonger.com"><img src="https://avatars2.githubusercontent.com/u/2037007?v=4" width="100px;" alt=""/><br /><sub><b>James Monger</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=Jameskmonger" title="Documentation">📖</a></td>
<td align="center"><a href="http://wesssel.github.io/"><img src="https://avatars2.githubusercontent.com/u/7767299?v=4" width="100px;" alt=""/><br /><sub><b>Wessel van der Pal</b></sub></a><br /><a href="#security-wesssel" title="Security">🛡️</a></td>
<td align="center"><a href="https://jung-kim.github.io"><img src="https://avatars2.githubusercontent.com/u/5281068?v=4" width="100px;" alt=""/><br /><sub><b>jk-kim</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=jung-kim" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/sss0791"><img src="https://avatars1.githubusercontent.com/u/1446970?v=4" width="100px;" alt=""/><br /><sub><b>Sergey Semenov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Asss0791" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://researcher.watson.ibm.com/researcher/view.php?person=us-nickm"><img src="https://avatars3.githubusercontent.com/u/4741620?v=4" width="100px;" alt=""/><br /><sub><b>Nick Mitchell</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Astarpit" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/samiraguiar"><img src="https://avatars0.githubusercontent.com/u/13439135?v=4" width="100px;" alt=""/><br /><sub><b>Samir Aguiar</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=samiraguiar" title="Documentation">📖</a></td>
<td align="center"><a href="https://saino.me/"><img src="https://avatars0.githubusercontent.com/u/1567423?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Koki Oyatsu</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Akaishuu0123" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=kaishuu0123" title="Code">💻</a></td>
<td align="center"><a href="http://www.jamesmonger.com"><img src="https://avatars2.githubusercontent.com/u/2037007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Monger</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=Jameskmonger" title="Documentation">📖</a></td>
<td align="center"><a href="http://wesssel.github.io/"><img src="https://avatars2.githubusercontent.com/u/7767299?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wessel van der Pal</b></sub></a><br /><a href="#security-wesssel" title="Security">🛡️</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=wesssel" title="Code">💻</a></td>
<td align="center"><a href="https://jung-kim.github.io"><img src="https://avatars2.githubusercontent.com/u/5281068?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jk-kim</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=jung-kim" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/sss0791"><img src="https://avatars1.githubusercontent.com/u/1446970?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sergey Semenov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Asss0791" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=sss0791" title="Code">💻</a></td>
<td align="center"><a href="http://researcher.watson.ibm.com/researcher/view.php?person=us-nickm"><img src="https://avatars3.githubusercontent.com/u/4741620?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nick Mitchell</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Astarpit" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=starpit" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/samiraguiar"><img src="https://avatars0.githubusercontent.com/u/13439135?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Samir Aguiar</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=samiraguiar" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://twitter.com/pubkeypubkey"><img src="https://avatars3.githubusercontent.com/u/8926560?v=4" width="100px;" alt=""/><br /><sub><b>pubkey</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=pubkey" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/iliyaZelenko"><img src="https://avatars1.githubusercontent.com/u/13103045?v=4" width="100px;" alt=""/><br /><sub><b>Илья</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=iliyaZelenko" title="Documentation">📖</a></td>
<td align="center"><a href="https://akr.am"><img src="https://avatars0.githubusercontent.com/u/1823771?v=4" width="100px;" alt=""/><br /><sub><b>Mohamed Akram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Amohd-akram" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/emarcotte"><img src="https://avatars0.githubusercontent.com/u/249390?v=4" width="100px;" alt=""/><br /><sub><b>Eugene Marcotte</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=emarcotte" title="Code">💻</a></td>
<td align="center"><a href="http://twitter.com/dimasabanin"><img src="https://avatars0.githubusercontent.com/u/8316?v=4" width="100px;" alt=""/><br /><sub><b>Dima Sabanin</b></sub></a><br /><a href="#maintenance-dsabanin" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/benabbottnz"><img src="https://avatars2.githubusercontent.com/u/2616473?v=4" width="100px;" alt=""/><br /><sub><b>Ben Abbott</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=benabbottnz" title="Documentation">📖</a></td>
<td align="center"><a href="http://webminer.js.org"><img src="https://avatars1.githubusercontent.com/u/2196373?v=4" width="100px;" alt=""/><br /><sub><b>弘树@阿里</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Adickeylth" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://twitter.com/pubkeypubkey"><img src="https://avatars3.githubusercontent.com/u/8926560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pubkey</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=pubkey" title="Documentation">📖</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=pubkey" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/iliyaZelenko"><img src="https://avatars1.githubusercontent.com/u/13103045?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Илья</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=iliyaZelenko" title="Documentation">📖</a></td>
<td align="center"><a href="https://akr.am"><img src="https://avatars0.githubusercontent.com/u/1823771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mohamed Akram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Amohd-akram" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=mohd-akram" title="Documentation">📖</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=mohd-akram" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/emarcotte"><img src="https://avatars0.githubusercontent.com/u/249390?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eugene Marcotte</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=emarcotte" title="Code">💻</a></td>
<td align="center"><a href="http://twitter.com/dimasabanin"><img src="https://avatars0.githubusercontent.com/u/8316?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dima Sabanin</b></sub></a><br /><a href="#maintenance-dsabanin" title="Maintenance">🚧</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=dsabanin" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/benabbottnz"><img src="https://avatars2.githubusercontent.com/u/2616473?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ben Abbott</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=benabbottnz" title="Documentation">📖</a></td>
<td align="center"><a href="http://webminer.js.org"><img src="https://avatars1.githubusercontent.com/u/2196373?v=4?s=100" width="100px;" alt=""/><br /><sub><b>弘树@阿里</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Adickeylth" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=dickeylth" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/Rantanen"><img src="https://avatars0.githubusercontent.com/u/385385?v=4" width="100px;" alt=""/><br /><sub><b>Mikko Rantanen</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3ARantanen" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/extend1994"><img src="https://avatars2.githubusercontent.com/u/13430892?v=4" width="100px;" alt=""/><br /><sub><b>Ann</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=extend1994" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/escitalopram"><img src="https://avatars0.githubusercontent.com/u/1155220?v=4" width="100px;" alt=""/><br /><sub><b>escitalopram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Aescitalopram" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=escitalopram" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apps/dependabot"><img src="https://avatars0.githubusercontent.com/in/29110?v=4" width="100px;" alt=""/><br /><sub><b>dependabot[bot]</b></sub></a><br /><a href="#security-dependabot[bot]" title="Security">🛡️</a> <a href="#maintenance-dependabot[bot]" title="Maintenance">🚧</a></td>
<td align="center"><a href="http://www.joshuakgoldberg.com"><img src="https://avatars1.githubusercontent.com/u/3335181?v=4" width="100px;" alt=""/><br /><sub><b>Josh Goldberg</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=JoshuaKGoldberg" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Rantanen"><img src="https://avatars0.githubusercontent.com/u/385385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mikko Rantanen</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3ARantanen" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/extend1994"><img src="https://avatars2.githubusercontent.com/u/13430892?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ann</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=extend1994" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/escitalopram"><img src="https://avatars0.githubusercontent.com/u/1155220?v=4?s=100" width="100px;" alt=""/><br /><sub><b>escitalopram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=escitalopram" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apps/dependabot"><img src="https://avatars0.githubusercontent.com/in/29110?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dependabot[bot]</b></sub></a><br /><a href="#security-dependabot[bot]" title="Security">🛡️</a> <a href="#maintenance-dependabot[bot]" title="Maintenance">🚧</a></td>
<td align="center"><a href="http://www.joshuakgoldberg.com"><img src="https://avatars1.githubusercontent.com/u/3335181?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Josh Goldberg</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=JoshuaKGoldberg" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apeckham"><img src="https://avatars.githubusercontent.com/u/14110?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aaron</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=apeckham" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/pgrimaud"><img src="https://avatars.githubusercontent.com/u/1866496?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pierre Grimaud</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=pgrimaud" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://domdomegg.github.io/"><img src="https://avatars.githubusercontent.com/u/4953590?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adam Jones</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=domdomegg" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/charguer"><img src="https://avatars.githubusercontent.com/u/1830652?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arthur Charguéraud</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=charguer" title="Documentation">📖</a></td>
<td align="center"><a href="https://twitter.com/pierrci"><img src="https://avatars.githubusercontent.com/u/5020707?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pierric Cistac</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=Pierrci" title="Documentation">📖</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=Pierrci" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/xlith"><img src="https://avatars.githubusercontent.com/u/510560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Civan Yavuzşen</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=xlith" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/timgates42"><img src="https://avatars.githubusercontent.com/u/47873678?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Gates</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=timgates42" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/campersau"><img src="https://avatars.githubusercontent.com/u/4009570?v=4?s=100" width="100px;" alt=""/><br /><sub><b>campersau</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=campersau" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apps/dependabot-preview"><img src="https://avatars.githubusercontent.com/in/2141?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dependabot-preview[bot]</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=dependabot-preview[bot]" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-enable -->
<!-- markdownlint-restore -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

77
eslint.config.mjs Normal file
View file

@ -0,0 +1,77 @@
import globals from 'globals';
import eslint from '@eslint/js';
import tseslint from 'typescript-eslint';
import pluginJest from 'eslint-plugin-jest';
import json from '@eslint/json';
import pluginPromise from 'eslint-plugin-promise';
export default [
{ ...eslint.configs.recommended, files: ['src/**/*.{js,mjs,cjs,ts}'] },
...tseslint.configs.recommended,
// ...tseslint.configs.recommendedTypeChecked,
// ...tseslint.configs.strict,
// ...tseslint.configs.stylistic,
// ...tseslint.configs.strictTypeChecked,
// ...tseslint.configs.stylisticTypeChecked,
{
rules: {
'@typescript-eslint/no-unused-vars': [
'error',
{
args: 'all',
argsIgnorePattern: '^_',
caughtErrors: 'all',
caughtErrorsIgnorePattern: '^_',
destructuredArrayIgnorePattern: '^_',
varsIgnorePattern: '^_',
ignoreRestSiblings: true,
},
],
},
},
pluginPromise.configs['flat/recommended'],
{
plugins: {
json,
},
files: ['**/*.json'],
language: 'json/json',
rules: {
'json/no-duplicate-keys': 'error',
},
},
{
...pluginJest.configs['flat/recommended'],
...pluginJest.configs['flat/style'],
files: ['src/__tests__/**/*tests.ts'],
plugins: { jest: pluginJest },
languageOptions: {
globals: pluginJest.environments.globals.globals,
},
},
{
languageOptions: {
globals: {
...globals.browser,
...globals.node,
...globals.es2025,
Atomics: 'readonly',
SharedArrayBuffer: 'readonly',
document: 'readonly',
navigator: 'readonly',
window: 'readonly',
},
parserOptions: {
project: './tsconfig.eslint.json',
tsconfigRootDir: './',
},
},
},
{
ignores: ['src/diff2html-templates.*', 'coverage/', 'docs/', 'bundles-out/', 'bundles/', 'lib/', 'lib-esm/'],
},
{
...tseslint.configs.disableTypeChecked,
files: ['**/*.{js,mjs,cjs}'],
},
];

View file

@ -19,4 +19,5 @@ module.exports = {
lines: 93,
},
},
prettierPath: require.resolve('prettier-2'),
};

18121
package-lock.json generated Normal file

File diff suppressed because it is too large Load diff

View file

@ -32,46 +32,42 @@
"url": "https://www.github.com/rtfpessoa/diff2html/issues"
},
"engines": {
"node": ">=10.13"
"node": ">=12"
},
"scripts": {
"eslint": "eslint --ignore-path .gitignore \"**/*.{js,jsx,ts,tsx,json}\"",
"lint:check": "yarn run eslint",
"lint:fix": "yarn run eslint --fix",
"lint:staged": "lint-staged",
"lint:check": "eslint",
"lint:fix": "eslint --fix",
"prettier": "prettier --ignore-path .gitignore '**/*.+(js|jsx|ts|tsx|json|css|html|md|mdx)'",
"format:check": "yarn run prettier --check",
"format:fix": "yarn run prettier --write",
"build": "yarn run build:css && yarn run build:templates && yarn run build:es5 && yarn run build:esm && yarn run build:bundles && yarn run build:website",
"build:es5": "rm -rf lib; tsc -p tsconfig.json --outDir lib",
"build:esm": "rm -rf lib-esm; tsc -p tsconfig.json -m es6 --outDir lib-esm",
"build:bundles": "rm -rf ./bundles/js; webpack ---display-reasons --display-modules --mode production --config webpack.bundles.ts",
"format:check": "npm run prettier --check",
"format:fix": "npm run prettier --write",
"build": "npm run build:css && npm run build:templates && npm run build:commonjs && npm run build:esm && npm run build:bundles && npm run build:website",
"build:commonjs": "rm -rf lib; tsc -p tsconfig.json -m CommonJS --outDir lib",
"build:esm": "rm -rf lib-esm; tsc -p tsconfig.json -m ESNext --outDir lib-esm",
"build:bundles": "rm -rf ./bundles/js; webpack --mode production --config webpack.bundles.ts",
"build:css": "rm -rf ./bundles/css; postcss --config ./postcss.config.js --no-map -o ./bundles/css/diff2html.min.css ./src/ui/css/diff2html.css",
"build:templates": "ts-node ./scripts/hulk.ts --wrapper ts --variable 'defaultTemplates' ./src/templates/*.mustache > ./src/diff2html-templates.ts",
"build:website": "rm -rf docs; webpack ---display-reasons --display-modules --mode production --config webpack.website.ts",
"gen": "yarn run gen:toc",
"build:website": "rm -rf docs; webpack --mode production --config webpack.website.ts",
"gen": "npm run gen:toc",
"gen:toc-base": "markdown-toc --maxdepth 3 --bullets='-' -i",
"gen:toc": "yarn run gen:toc-base README.md",
"gen:toc": "npm run gen:toc-base README.md",
"test": "is-ci 'test:coverage' 'test:watch'",
"test:coverage": "jest --coverage",
"test:watch": "jest --watch",
"test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand --watch",
"coverage:open": "yarn run test:coverage && open ./coverage/index.html",
"coverage:push": "cat ./coverage/lcov.info | codacy-coverage",
"validate": "yarn run build:templates && yarn run format:check && yarn run lint:check && yarn run build && yarn run test:coverage",
"fix": "yarn run format:fix && yarn run lint:fix",
"start": "yarn run start:website",
"start:website": "webpack-dev-server --mode development --config webpack.website.ts",
"preversion": "yarn run validate",
"version": "git add -A package.json"
"coverage:open": "npm run test:coverage && open ./coverage/index.html",
"coverage:push": "curl -Ls https://coverage.codacy.com/get.sh | bash",
"validate": "npm run build:templates && npm run format:check && npm run lint:check && npm run build && npm run test:coverage",
"fix": "npm run format:fix && npm run lint:fix",
"start": "npm run start:website",
"start:website": "webpack serve --mode development --config webpack.website.ts",
"preversion": "npm run validate",
"version": "git add -A package.json",
"prepare": "husky"
},
"main": "./lib/diff2html.js",
"module": "./lib-esm/diff2html.js",
"types": "./lib/diff2html.d.ts",
"husky": {
"hooks": {
"pre-commit": "lint-staged"
}
},
"lint-staged": {
"**/*.+(js|jsx|ts|tsx|json)": [
"prettier --write",
@ -81,78 +77,79 @@
"prettier --write"
],
"README.md": [
"yarn run gen:toc-base"
"npm run gen:toc-base"
]
},
"dependencies": {
"diff": "4.0.2",
"diff": "^7.0.0",
"hogan.js": "3.0.2"
},
"optionalDependencies": {
"highlight.js": "9.18.1"
"highlight.js": "11.9.0"
},
"devDependencies": {
"@types/clipboard": "2.0.1",
"@types/copy-webpack-plugin": "5.0.0",
"@types/diff": "4.0.2",
"@types/highlight.js": "9.12.3",
"@types/hogan.js": "3.0.0",
"@types/html-webpack-plugin": "3.2.2",
"@types/jest": "25.1.1",
"@types/mini-css-extract-plugin": "0.9.0",
"@types/mkdirp": "0.5.2",
"@types/node": "13.7.0",
"@types/nopt": "3.0.29",
"@types/webpack": "4.41.5",
"@typescript-eslint/eslint-plugin": "2.19.0",
"@typescript-eslint/parser": "2.19.0",
"autoprefixer": "9.7.4",
"bulma": "^0.8.0",
"clipboard": "2.0.4",
"codacy-coverage": "3.4.0",
"copy-webpack-plugin": "5.1.1",
"css-loader": "3.4.2",
"cssnano": "4.1.10",
"eslint": "6.8.0",
"eslint-config-prettier": "6.10.0",
"eslint-plugin-import": "2.20.1",
"eslint-plugin-jest": "23.6.0",
"eslint-plugin-json": "2.0.1",
"eslint-plugin-node": "11.0.0",
"eslint-plugin-optimize-regex": "1.1.7",
"eslint-plugin-promise": "4.2.1",
"eslint-plugin-sonarjs": "0.5.0",
"file-loader": "5.0.2",
"handlebars": "4.7.3",
"handlebars-loader": "1.7.1",
"html-webpack-plugin": "3.2.0",
"husky": "4.2.1",
"image-webpack-loader": "6.0.0",
"is-ci-cli": "2.0.0",
"jest": "25.1.0",
"lint-staged": "10.0.7",
"prettier-2": "npm:prettier@^2",
"@eslint/js": "^9.17.0",
"@eslint/json": "^0.9.0",
"@types/diff": "^6.0.0",
"@types/hogan.js": "3.0.5",
"@types/jest": "^29.5.14",
"@types/node": "^22.10.2",
"@types/nopt": "3.0.32",
"all-contributors-cli": "^6.24.0",
"autoprefixer": "^10.4.20",
"bulma": "^1.0.2",
"clipboard": "2.0.11",
"copy-webpack-plugin": "^12.0.2",
"css-loader": "^7.1.2",
"cssnano": "^7.0.6",
"eslint": "^9.17.0",
"eslint-plugin-jest": "28.10.0",
"eslint-plugin-promise": "^7.2.1",
"file-loader": "6.2.0",
"globals": "^15.14.0",
"handlebars": "4.7.8",
"handlebars-loader": "1.7.3",
"html-webpack-plugin": "^5.6.3",
"husky": "^9.1.7",
"image-webpack-loader": "8.1.0",
"is-ci-cli": "2.2.0",
"jest": "29.7.0",
"lint-staged": "^15.2.11",
"markdown-toc": "^1.2.0",
"mini-css-extract-plugin": "0.9.0",
"mkdirp": "1.0.3",
"nopt": "4.0.1",
"postcss": "7.0.26",
"postcss-cli": "7.1.0",
"postcss-import": "12.0.1",
"postcss-loader": "3.0.0",
"postcss-preset-env": "6.7.0",
"prettier": "1.19.1",
"ts-jest": "25.2.0",
"ts-loader": "6.2.1",
"ts-node": "8.6.2",
"typescript": "3.7.5",
"url-loader": "3.0.0",
"webpack": "4.41.5",
"webpack-cli": "3.3.10",
"webpack-dev-server": "3.10.3",
"whatwg-fetch": "3.0.0"
"mini-css-extract-plugin": "^2.9.2",
"mkdirp": "3.0.1",
"nopt": "^8.0.0",
"postcss": "^8.4.49",
"postcss-cli": "11.0.0",
"postcss-import": "^16.1.0",
"postcss-loader": "^8.1.1",
"postcss-preset-env": "^10.1.2",
"prettier": "^3.4.2",
"ts-jest": "^29.2.5",
"ts-loader": "9.5.1",
"ts-node": "10.9.2",
"typescript": "^5.7.2",
"typescript-eslint": "^8.18.2",
"url-loader": "4.1.1",
"webpack": "^5.97.1",
"webpack-cli": "^6.0.1",
"webpack-dev-server": "^5.2.0",
"whatwg-fetch": "3.6.20"
},
"resolutions": {
"lodash": "4.17.15"
"lodash": ">=4.17.20",
"minimist": ">=1.2.5",
"acorn": ">=7.4.0",
"autolinker": ">=3.14.1",
"bl": ">=2.2.1",
"decompress": ">=4.2.1",
"node-forge": ">=0.10.0",
"trim-newlines": ">=3.0.1",
"async": ">=2.6.4",
"terser": ">=5.14.2",
"semver-regex": ">=4.0.5",
"http-cache-semantics": ">=4.1.1"
},
"license": "MIT",
"files": [

View file

@ -67,6 +67,7 @@ function extractFiles(files: string[]): string[] {
`;
if (options.version) {
// eslint-disable-next-line @typescript-eslint/no-require-imports
console.log(require('../package.json').version);
process.exit(0);
}

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View file

@ -1,176 +0,0 @@
import { render } from '../file-list-renderer';
import HoganJsUtils from '../hoganjs-utils';
describe('FileListPrinter', () => {
describe('generateFileList', () => {
it('should expose old and new files to templates', () => {
const hoganUtils = new HoganJsUtils({
rawTemplates: {
'file-summary-wrapper': '{{{files}}}',
'file-summary-line': '{{oldName}}, {{newName}}, {{fileName}}',
},
});
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name1.js',
newName: 'my/file/name2.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 0,
language: 'js',
oldName: 'dev/null',
newName: 'my/file/name.js',
isNew: true,
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 0,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'dev/null',
isDeleted: true,
},
];
const fileHtml = render(files, hoganUtils);
expect(fileHtml).toMatchInlineSnapshot(`
"my/file/name.js, my/file/name.js, my/file/name.js
my/file/name1.js, my/file/name2.js, my/file/{name1.js name2.js}
dev/null, my/file/name.js, my/file/name.js
my/file/name.js, dev/null, my/file/name.js"
`);
});
it('should work for all kinds of files', () => {
const hoganUtils = new HoganJsUtils({});
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name1.js',
newName: 'my/file/name2.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 0,
language: 'js',
oldName: 'dev/null',
newName: 'my/file/name.js',
isNew: true,
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 0,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'dev/null',
isDeleted: true,
},
];
const fileHtml = render(files, hoganUtils);
expect(fileHtml).toMatchInlineSnapshot(`
"<div class=\\"d2h-file-list-wrapper\\">
<div class=\\"d2h-file-list-header\\">
<span class=\\"d2h-file-list-title\\">Files changed (4)</span>
<a class=\\"d2h-file-switch d2h-hide\\">hide</a>
<a class=\\"d2h-file-switch d2h-show\\">show</a>
</div>
<ol class=\\"d2h-file-list\\">
<li class=\\"d2h-file-list-line\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon d2h-changed\\" height=\\"16\\" title=\\"modified\\" version=\\"1.1\\"
viewBox=\\"0 0 14 16\\" width=\\"14\\">
<path d=\\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z\\"></path>
</svg> <a href=\\"#d2h-781444\\" class=\\"d2h-file-name\\">my/file/name.js</a>
<span class=\\"d2h-file-stats\\">
<span class=\\"d2h-lines-added\\">+12</span>
<span class=\\"d2h-lines-deleted\\">-41</span>
</span>
</span>
</li>
<li class=\\"d2h-file-list-line\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon d2h-moved\\" height=\\"16\\" title=\\"renamed\\" version=\\"1.1\\"
viewBox=\\"0 0 14 16\\" width=\\"14\\">
<path d=\\"M6 9H3V7h3V4l5 4-5 4V9z m8-7v12c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h12c0.55 0 1 0.45 1 1z m-1 0H1v12h12V2z\\"></path>
</svg> <a href=\\"#d2h-662683\\" class=\\"d2h-file-name\\">my/file/{name1.js name2.js}</a>
<span class=\\"d2h-file-stats\\">
<span class=\\"d2h-lines-added\\">+12</span>
<span class=\\"d2h-lines-deleted\\">-41</span>
</span>
</span>
</li>
<li class=\\"d2h-file-list-line\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon d2h-added\\" height=\\"16\\" title=\\"added\\" version=\\"1.1\\" viewBox=\\"0 0 14 16\\"
width=\\"14\\">
<path d=\\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM6 9H3V7h3V4h2v3h3v2H8v3H6V9z\\"></path>
</svg> <a href=\\"#d2h-781444\\" class=\\"d2h-file-name\\">my/file/name.js</a>
<span class=\\"d2h-file-stats\\">
<span class=\\"d2h-lines-added\\">+12</span>
<span class=\\"d2h-lines-deleted\\">-0</span>
</span>
</span>
</li>
<li class=\\"d2h-file-list-line\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon d2h-deleted\\" height=\\"16\\" title=\\"removed\\" version=\\"1.1\\"
viewBox=\\"0 0 14 16\\" width=\\"14\\">
<path d=\\"M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM11 9H3V7h8v2z\\"></path>
</svg> <a href=\\"#d2h-781444\\" class=\\"d2h-file-name\\">my/file/name.js</a>
<span class=\\"d2h-file-stats\\">
<span class=\\"d2h-lines-added\\">+0</span>
<span class=\\"d2h-lines-deleted\\">-41</span>
</span>
</span>
</li>
</ol>
</div>"
`);
});
});
});

View file

@ -0,0 +1,272 @@
import { FileListRenderer } from '../file-list-renderer';
import HoganJsUtils from '../hoganjs-utils';
import { ColorSchemeType } from '../types';
describe('FileListRenderer', () => {
describe('render', () => {
it('should expose old and new files to templates', () => {
const hoganUtils = new HoganJsUtils({
rawTemplates: {
'file-summary-wrapper': '{{{files}}}',
'file-summary-line': '{{oldName}}, {{newName}}, {{fileName}}',
},
});
const fileListRenderer = new FileListRenderer(hoganUtils);
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name1.js',
newName: 'my/file/name2.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 0,
language: 'js',
oldName: 'dev/null',
newName: 'my/file/name.js',
isNew: true,
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 0,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'dev/null',
isDeleted: true,
},
];
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"my/file/name.js, my/file/name.js, my/file/name.js
my/file/name1.js, my/file/name2.js, my/file/{name1.js name2.js}
dev/null, my/file/name.js, my/file/name.js
my/file/name.js, dev/null, my/file/name.js"
`);
});
it('should work for all kinds of files', () => {
const hoganUtils = new HoganJsUtils({});
const fileListRenderer = new FileListRenderer(hoganUtils);
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name1.js',
newName: 'my/file/name2.js',
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 0,
language: 'js',
oldName: 'dev/null',
newName: 'my/file/name.js',
isNew: true,
},
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 0,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'dev/null',
isDeleted: true,
},
];
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper d2h-light-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (4)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
<a class="d2h-file-switch d2h-show">show</a>
</div>
<ol class="d2h-file-list">
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-changed" height="16" title="modified" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"></path>
</svg> <a href="#d2h-781444" class="d2h-file-name">my/file/name.js</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+12</span>
<span class="d2h-lines-deleted">-41</span>
</span>
</span>
</li>
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-moved" height="16" title="renamed" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M6 9H3V7h3V4l5 4-5 4V9z m8-7v12c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h12c0.55 0 1 0.45 1 1z m-1 0H1v12h12V2z"></path>
</svg> <a href="#d2h-662683" class="d2h-file-name">my/file/{name1.js name2.js}</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+12</span>
<span class="d2h-lines-deleted">-41</span>
</span>
</span>
</li>
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-added" height="16" title="added" version="1.1" viewBox="0 0 14 16"
width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM6 9H3V7h3V4h2v3h3v2H8v3H6V9z"></path>
</svg> <a href="#d2h-781444" class="d2h-file-name">my/file/name.js</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+12</span>
<span class="d2h-lines-deleted">-0</span>
</span>
</span>
</li>
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-deleted" height="16" title="removed" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM11 9H3V7h8v2z"></path>
</svg> <a href="#d2h-781444" class="d2h-file-name">my/file/name.js</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+0</span>
<span class="d2h-lines-deleted">-41</span>
</span>
</span>
</li>
</ol>
</div>"
`);
});
describe('with dark colorScheme', () => {
it('should include dark colorScheme', () => {
const hoganUtils = new HoganJsUtils({});
const fileListRenderer = new FileListRenderer(hoganUtils, {
colorScheme: ColorSchemeType.DARK,
});
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
];
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper d2h-dark-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
<a class="d2h-file-switch d2h-show">show</a>
</div>
<ol class="d2h-file-list">
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-changed" height="16" title="modified" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"></path>
</svg> <a href="#d2h-781444" class="d2h-file-name">my/file/name.js</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+12</span>
<span class="d2h-lines-deleted">-41</span>
</span>
</span>
</li>
</ol>
</div>"
`);
});
});
describe('with auto colorScheme', () => {
it('should include auto colorScheme', () => {
const hoganUtils = new HoganJsUtils({});
const fileListRenderer = new FileListRenderer(hoganUtils, {
colorScheme: ColorSchemeType.AUTO,
});
const files = [
{
isCombined: false,
isGitDiff: false,
blocks: [],
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
},
];
const fileHtml = fileListRenderer.render(files);
expect(fileHtml).toMatchInlineSnapshot(`
"<div class="d2h-file-list-wrapper d2h-auto-color-scheme">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed (1)</span>
<a class="d2h-file-switch d2h-hide">hide</a>
<a class="d2h-file-switch d2h-show">show</a>
</div>
<ol class="d2h-file-list">
<li class="d2h-file-list-line">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon d2h-changed" height="16" title="modified" version="1.1"
viewBox="0 0 14 16" width="14">
<path d="M13 1H1C0.45 1 0 1.45 0 2v12c0 0.55 0.45 1 1 1h12c0.55 0 1-0.45 1-1V2c0-0.55-0.45-1-1-1z m0 13H1V2h12v12zM4 8c0-1.66 1.34-3 3-3s3 1.34 3 3-1.34 3-3 3-3-1.34-3-3z"></path>
</svg> <a href="#d2h-781444" class="d2h-file-name">my/file/name.js</a>
<span class="d2h-file-stats">
<span class="d2h-lines-added">+12</span>
<span class="d2h-lines-deleted">-41</span>
</span>
</span>
</li>
</ol>
</div>"
`);
});
});
});
});

View file

@ -11,8 +11,8 @@ describe('HoganJsUtils', () => {
});
expect(result).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-line d2h-info\\">
<td class="d2h-info">
<div class="d2h-code-line">
File without changes
</div>
</td>

View file

@ -11,8 +11,8 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.generateEmptyDiff();
expect(fileHtml).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-line d2h-info\\">
<td class="d2h-info">
<div class="d2h-code-line">
File without changes
</div>
</td>
@ -23,9 +23,19 @@ describe('LineByLineRenderer', () => {
describe('makeLineHtml', () => {
it('should work for insertions', () => {
const file = {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
isCombined: false,
isGitDiff: false,
blocks: [],
};
const hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS,
prefix: '+',
content: 'test',
@ -34,14 +44,14 @@ describe('LineByLineRenderer', () => {
});
expect(fileHtml).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\">
<div class=\\"line-num1\\"></div>
<div class=\\"line-num2\\">30</div>
<td class="d2h-code-linenumber d2h-ins">
<div class="line-num1"></div>
<div class="line-num2">30</div>
</td>
<td class=\\"d2h-ins\\">
<div class=\\"d2h-code-line d2h-ins\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\">test</span>
<td class="d2h-ins">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn">test</span>
</div>
</td>
</tr>"
@ -49,9 +59,19 @@ describe('LineByLineRenderer', () => {
});
it('should work for deletions', () => {
const file = {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
isCombined: false,
isGitDiff: false,
blocks: [],
};
const hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.DELETES,
prefix: '-',
content: 'test',
@ -60,14 +80,14 @@ describe('LineByLineRenderer', () => {
});
expect(fileHtml).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-code-linenumber d2h-del\\">
<div class=\\"line-num1\\">30</div>
<div class=\\"line-num2\\"></div>
<td class="d2h-code-linenumber d2h-del">
<div class="line-num1">30</div>
<div class="line-num2"></div>
</td>
<td class=\\"d2h-del\\">
<div class=\\"d2h-code-line d2h-del\\">
<span class=\\"d2h-code-line-prefix\\">-</span>
<span class=\\"d2h-code-line-ctn\\">test</span>
<td class="d2h-del">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn">test</span>
</div>
</td>
</tr>"
@ -75,9 +95,19 @@ describe('LineByLineRenderer', () => {
});
it('should convert indents into non breakin spaces (2 white spaces)', () => {
const file = {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
isCombined: false,
isGitDiff: false,
blocks: [],
};
const hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS,
prefix: '+',
content: ' test',
@ -86,14 +116,14 @@ describe('LineByLineRenderer', () => {
});
expect(fileHtml).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\">
<div class=\\"line-num1\\"></div>
<div class=\\"line-num2\\">30</div>
<td class="d2h-code-linenumber d2h-ins">
<div class="line-num1"></div>
<div class="line-num2">30</div>
</td>
<td class=\\"d2h-ins\\">
<div class=\\"d2h-code-line d2h-ins\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"> test</span>
<td class="d2h-ins">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"> test</span>
</div>
</td>
</tr>"
@ -101,9 +131,19 @@ describe('LineByLineRenderer', () => {
});
it('should convert indents into non breakin spaces (4 white spaces)', () => {
const file = {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
isCombined: false,
isGitDiff: false,
blocks: [],
};
const hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS,
prefix: '+',
content: ' test',
@ -112,14 +152,14 @@ describe('LineByLineRenderer', () => {
});
expect(fileHtml).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\">
<div class=\\"line-num1\\"></div>
<div class=\\"line-num2\\">30</div>
<td class="d2h-code-linenumber d2h-ins">
<div class="line-num1"></div>
<div class="line-num2">30</div>
</td>
<td class=\\"d2h-ins\\">
<div class=\\"d2h-code-line d2h-ins\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"> test</span>
<td class="d2h-ins">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"> test</span>
</div>
</td>
</tr>"
@ -127,9 +167,19 @@ describe('LineByLineRenderer', () => {
});
it('should preserve tabs', () => {
const file = {
addedLines: 12,
deletedLines: 41,
language: 'js',
oldName: 'my/file/name.js',
newName: 'my/file/name.js',
isCombined: false,
isGitDiff: false,
blocks: [],
};
const hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS,
prefix: '+',
content: '\ttest',
@ -138,14 +188,14 @@ describe('LineByLineRenderer', () => {
});
expect(fileHtml).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\">
<div class=\\"line-num1\\"></div>
<div class=\\"line-num2\\">30</div>
<td class="d2h-code-linenumber d2h-ins">
<div class="line-num1"></div>
<div class="line-num2">30</div>
</td>
<td class=\\"d2h-ins\\">
<div class=\\"d2h-code-line d2h-ins\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"> test</span>
<td class="d2h-ins">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"> test</span>
</div>
</td>
</tr>"
@ -173,18 +223,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-781444\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">my/file/name.js</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span>
"<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">my/file/name.js</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-file-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<span>Random Html</span>
</tbody>
</table>
@ -213,18 +267,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-781444\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">my/file/name.js</span>
<span class=\\"d2h-tag d2h-added d2h-added-tag\\">ADDED</span></span>
"<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">my/file/name.js</span>
<span class="d2h-tag d2h-added d2h-added-tag">ADDED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-file-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<span>Random Html</span>
</tbody>
</table>
@ -253,18 +311,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-781444\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">my/file/name.js</span>
<span class=\\"d2h-tag d2h-deleted d2h-deleted-tag\\">DELETED</span></span>
"<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">my/file/name.js</span>
<span class="d2h-tag d2h-deleted d2h-deleted-tag">DELETED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-file-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<span>Random Html</span>
</tbody>
</table>
@ -293,18 +355,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-662683\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">my/file/{name1.js name2.js}</span>
<span class=\\"d2h-tag d2h-moved d2h-moved-tag\\">RENAMED</span></span>
"<div id="d2h-662683" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">my/file/{name1.js name2.js}</span>
<span class="d2h-tag d2h-moved d2h-moved-tag">RENAMED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-file-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<span>Random Html</span>
</tbody>
</table>
@ -383,44 +449,48 @@ describe('LineByLineRenderer', () => {
});
const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"txt\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span>
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="txt">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-file-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class=\\"d2h-code-linenumber d2h-info\\"></td>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-line d2h-info\\">@@ -1 +1 @@</div>
<td class="d2h-code-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-line">@@ -1 +1 @@</div>
</td>
</tr><tr>
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\">
<div class=\\"line-num1\\">1</div>
<div class=\\"line-num2\\"></div>
<td class="d2h-code-linenumber d2h-del d2h-change">
<div class="line-num1">1</div>
<div class="line-num2"></div>
</td>
<td class=\\"d2h-del d2h-change\\">
<div class=\\"d2h-code-line d2h-del d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span>
<td class="d2h-del d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\">
<div class=\\"line-num1\\"></div>
<div class=\\"line-num2\\">1</div>
<td class="d2h-code-linenumber d2h-ins d2h-change">
<div class="line-num1"></div>
<div class="line-num2">1</div>
</td>
<td class=\\"d2h-ins d2h-change\\">
<div class=\\"d2h-code-line d2h-ins d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span>
<td class="d2h-ins d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div>
</td>
</tr>
@ -453,22 +523,26 @@ describe('LineByLineRenderer', () => {
});
const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span>
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-file-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-line d2h-info\\">
<td class="d2h-info">
<div class="d2h-code-line">
File without changes
</div>
</td>
@ -481,6 +555,65 @@ describe('LineByLineRenderer', () => {
</div>"
`);
});
it('should work for too big file diff', () => {
const exampleJson = [
{
blocks: [
{
header: '<a href="http://example.com">Custom link to render</a>',
lines: [],
newStartLine: 0,
oldStartLine: 0,
oldStartLine2: undefined,
},
],
deletedLines: 0,
addedLines: 0,
oldName: 'sample',
language: 'js',
newName: 'sample',
isCombined: false,
isGitDiff: false,
isTooBig: true,
},
];
const hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils);
const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class="d2h-file-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class="d2h-code-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-line"><a href="http://example.com">Custom link to render</a></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>"
`);
});
});
describe('_generateFileHtml', () => {
@ -537,52 +670,52 @@ describe('LineByLineRenderer', () => {
expect(html).toMatchInlineSnapshot(`
"<tr>
<td class=\\"d2h-code-linenumber d2h-info\\"></td>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-line d2h-info\\">@@ -1 +1 @@</div>
<td class="d2h-code-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-line">@@ -1 +1 @@</div>
</td>
</tr><tr>
<td class=\\"d2h-code-linenumber d2h-cntx\\">
<div class=\\"line-num1\\">1</div>
<div class=\\"line-num2\\">1</div>
<td class="d2h-code-linenumber d2h-cntx">
<div class="line-num1">1</div>
<div class="line-num2">1</div>
</td>
<td class=\\"d2h-cntx\\">
<div class=\\"d2h-code-line d2h-cntx\\">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">one context line</span>
<td class="d2h-cntx">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">&nbsp;</span>
<span class="d2h-code-line-ctn">one context line</span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\">
<div class=\\"line-num1\\">2</div>
<div class=\\"line-num2\\"></div>
<td class="d2h-code-linenumber d2h-del d2h-change">
<div class="line-num1">2</div>
<div class="line-num2"></div>
</td>
<td class=\\"d2h-del d2h-change\\">
<div class=\\"d2h-code-line d2h-del d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span>
<td class="d2h-del d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\">
<div class=\\"line-num1\\"></div>
<div class=\\"line-num2\\">2</div>
<td class="d2h-code-linenumber d2h-ins d2h-change">
<div class="line-num1"></div>
<div class="line-num2">2</div>
</td>
<td class=\\"d2h-ins d2h-change\\">
<div class=\\"d2h-code-line d2h-ins d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span>
<td class="d2h-ins d2h-change">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-linenumber d2h-ins\\">
<div class=\\"line-num1\\"></div>
<div class=\\"line-num2\\">3</div>
<td class="d2h-code-linenumber d2h-ins">
<div class="line-num1"></div>
<div class="line-num2">3</div>
</td>
<td class=\\"d2h-ins\\">
<div class=\\"d2h-code-line d2h-ins\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\">test2r</span>
<td class="d2h-ins">
<div class="d2h-code-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn">test2r</span>
</div>
</td>
</tr>"

View file

@ -5,31 +5,31 @@ describe('Utils', () => {
describe('escapeForHtml', () => {
it('should escape & with &amp;', () => {
const result = escapeForHtml('&');
expect(result).toEqual('&amp;');
expect(result).toBe('&amp;');
});
it('should escape < with &lt;', () => {
const result = escapeForHtml('<');
expect(result).toEqual('&lt;');
expect(result).toBe('&lt;');
});
it('should escape > with &gt;', () => {
const result = escapeForHtml('>');
expect(result).toEqual('&gt;');
expect(result).toBe('&gt;');
});
it('should escape " with &quot;', () => {
const result = escapeForHtml('"');
expect(result).toEqual('&quot;');
expect(result).toBe('&quot;');
});
it("should escape ' with &#x27;", () => {
const result = escapeForHtml("'");
expect(result).toEqual('&#x27;');
expect(result).toBe('&#x27;');
});
it('should escape / with &#x2F;', () => {
const result = escapeForHtml('/');
expect(result).toEqual('&#x2F;');
expect(result).toBe('&#x2F;');
});
it('should escape a string containing HTML code', () => {
const result = escapeForHtml(`<a href="/search?q=diff2html">Search 'Diff2Html'</a>`);
expect(result).toEqual(
expect(result).toBe(
'&lt;a href=&quot;&#x2F;search?q=diff2html&quot;&gt;Search &#x27;Diff2Html&#x27;&lt;&#x2F;a&gt;',
);
});
@ -41,7 +41,7 @@ describe('Utils', () => {
oldName: 'sample.js',
newName: 'sample.js',
});
expect(result).toEqual('d2h-960013');
expect(result).toBe('d2h-960013');
});
});
@ -51,49 +51,49 @@ describe('Utils', () => {
oldName: 'sample.js',
newName: 'sample.js',
});
expect(result).toEqual('sample.js');
expect(result).toBe('sample.js');
});
it('should generate the file name for a changed file and full rename', () => {
const result = filenameDiff({
oldName: 'sample1.js',
newName: 'sample2.js',
});
expect(result).toEqual('sample1.js → sample2.js');
expect(result).toBe('sample1.js → sample2.js');
});
it('should generate the file name for a changed file and prefix rename', () => {
const result = filenameDiff({
oldName: 'src/path/sample.js',
newName: 'source/path/sample.js',
});
expect(result).toEqual('{src → source}/path/sample.js');
expect(result).toBe('{src → source}/path/sample.js');
});
it('should generate the file name for a changed file and suffix rename', () => {
const result = filenameDiff({
oldName: 'src/path/sample1.js',
newName: 'src/path/sample2.js',
});
expect(result).toEqual('src/path/{sample1.js → sample2.js}');
expect(result).toBe('src/path/{sample1.js → sample2.js}');
});
it('should generate the file name for a changed file and middle rename', () => {
const result = filenameDiff({
oldName: 'src/really/big/path/sample.js',
newName: 'src/small/path/sample.js',
});
expect(result).toEqual('src/{really/big → small}/path/sample.js');
expect(result).toBe('src/{really/big → small}/path/sample.js');
});
it('should generate the file name for a deleted file', () => {
const result = filenameDiff({
oldName: 'src/my/file.js',
newName: '/dev/null',
});
expect(result).toEqual('src/my/file.js');
expect(result).toBe('src/my/file.js');
});
it('should generate the file name for a new file', () => {
const result = filenameDiff({
oldName: '/dev/null',
newName: 'src/my/file.js',
});
expect(result).toEqual('src/my/file.js');
expect(result).toBe('src/my/file.js');
});
});

View file

@ -10,10 +10,10 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
const fileHtml = sideBySideRenderer.generateEmptyDiff();
expect(fileHtml).toMatchInlineSnapshot(`
Object {
{
"left": "<tr>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-side-line d2h-info\\">
<td class="d2h-info">
<div class="d2h-code-side-line">
File without changes
</div>
</td>
@ -78,76 +78,76 @@ describe('SideBySideRenderer', () => {
const fileHtml = sideBySideRenderer.generateFileHtml(file);
expect(fileHtml).toMatchInlineSnapshot(`
Object {
{
"left": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-side-line d2h-info\\">@@ -19,7 +19,7 @@</div>
<td class="d2h-code-side-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-side-line">@@ -19,7 +19,7 @@</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-cntx\\">
<td class="d2h-code-side-linenumber d2h-cntx">
19
</td>
<td class=\\"d2h-cntx\\">
<div class=\\"d2h-code-side-line d2h-cntx\\">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">context</span>
<td class="d2h-cntx">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">&nbsp;</span>
<span class="d2h-code-line-ctn">context</span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-del d2h-change\\">
<td class="d2h-code-side-linenumber d2h-del d2h-change">
20
</td>
<td class=\\"d2h-del d2h-change\\">
<div class=\\"d2h-code-side-line d2h-del d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>removed</del></span>
<td class="d2h-del d2h-change">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>removed</del></span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder\\">
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
</td>
<td class=\\"d2h-cntx d2h-emptyplaceholder\\">
<div class=\\"d2h-code-side-line d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder\\">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">&nbsp;</span>
<td class="d2h-cntx d2h-emptyplaceholder">
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
<span class="d2h-code-line-prefix">&nbsp;</span>
<span class="d2h-code-line-ctn"><br></span>
</div>
</td>
</tr>",
"right": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-side-line d2h-info\\"></div>
<td class="d2h-code-side-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-side-line">&nbsp;</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-cntx\\">
<td class="d2h-code-side-linenumber d2h-cntx">
19
</td>
<td class=\\"d2h-cntx\\">
<div class=\\"d2h-code-side-line d2h-cntx\\">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">context</span>
<td class="d2h-cntx">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">&nbsp;</span>
<span class="d2h-code-line-ctn">context</span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-ins d2h-change\\">
<td class="d2h-code-side-linenumber d2h-ins d2h-change">
20
</td>
<td class=\\"d2h-ins d2h-change\\">
<div class=\\"d2h-code-side-line d2h-ins d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>added</ins></span>
<td class="d2h-ins d2h-change">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>added</ins></span>
</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-ins\\">
<td class="d2h-code-side-linenumber d2h-ins">
21
</td>
<td class=\\"d2h-ins\\">
<div class=\\"d2h-code-side-line d2h-ins\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\">another added</span>
<td class="d2h-ins">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn">another added</span>
</div>
</td>
</tr>",
@ -168,26 +168,26 @@ describe('SideBySideRenderer', () => {
});
expect(fileHtml).toMatchInlineSnapshot(`
Object {
{
"left": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder\\">
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
</td>
<td class=\\"d2h-cntx d2h-emptyplaceholder\\">
<div class=\\"d2h-code-side-line d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder\\">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">&nbsp;</span>
<td class="d2h-cntx d2h-emptyplaceholder">
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
<span class="d2h-code-line-prefix">&nbsp;</span>
<span class="d2h-code-line-ctn"><br></span>
</div>
</td>
</tr>",
"right": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-ins\\">
<td class="d2h-code-side-linenumber d2h-ins">
30
</td>
<td class=\\"d2h-ins\\">
<div class=\\"d2h-code-side-line d2h-ins\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\">test</span>
<td class="d2h-ins">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn">test</span>
</div>
</td>
</tr>",
@ -208,26 +208,26 @@ describe('SideBySideRenderer', () => {
);
expect(fileHtml).toMatchInlineSnapshot(`
Object {
{
"left": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-del\\">
<td class="d2h-code-side-linenumber d2h-del">
30
</td>
<td class=\\"d2h-del\\">
<div class=\\"d2h-code-side-line d2h-del\\">
<span class=\\"d2h-code-line-prefix\\">-</span>
<span class=\\"d2h-code-line-ctn\\">test</span>
<td class="d2h-del">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn">test</span>
</div>
</td>
</tr>",
"right": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder\\">
<td class="d2h-code-side-linenumber d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder">
</td>
<td class=\\"d2h-cntx d2h-emptyplaceholder\\">
<div class=\\"d2h-code-side-line d2h-code-side-emptyplaceholder d2h-cntx d2h-emptyplaceholder\\">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">&nbsp;</span>
<td class="d2h-cntx d2h-emptyplaceholder">
<div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
<span class="d2h-code-line-prefix">&nbsp;</span>
<span class="d2h-code-line-ctn"><br></span>
</div>
</td>
</tr>",
@ -278,33 +278,37 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: LineMatchingType.LINES });
const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"txt\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span>
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="txt">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-files-diff\\">
<div class=\\"d2h-file-side-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-files-diff">
<div class="d2h-file-side-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-side-line d2h-info\\">@@ -1 +1 @@</div>
<td class="d2h-code-side-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-side-line">@@ -1 +1 @@</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-del d2h-change\\">
<td class="d2h-code-side-linenumber d2h-del d2h-change">
1
</td>
<td class=\\"d2h-del d2h-change\\">
<div class=\\"d2h-code-side-line d2h-del d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span>
<td class="d2h-del d2h-change">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr>
@ -312,23 +316,23 @@ describe('SideBySideRenderer', () => {
</table>
</div>
</div>
<div class=\\"d2h-file-side-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-side-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-side-line d2h-info\\"></div>
<td class="d2h-code-side-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-side-line">&nbsp;</div>
</td>
</tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-ins d2h-change\\">
<td class="d2h-code-side-linenumber d2h-ins d2h-change">
1
</td>
<td class=\\"d2h-ins d2h-change\\">
<div class=\\"d2h-code-side-line d2h-ins d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span>
<td class="d2h-ins d2h-change">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div>
</td>
</tr>
@ -359,23 +363,27 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\">
<div class=\\"d2h-file-header\\">
<span class=\\"d2h-file-name-wrapper\\">
<svg aria-hidden=\\"true\\" class=\\"d2h-icon\\" height=\\"16\\" version=\\"1.1\\" viewBox=\\"0 0 12 16\\" width=\\"12\\">
<path d=\\"M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z\\"></path>
</svg> <span class=\\"d2h-file-name\\">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span>
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class=\\"d2h-files-diff\\">
<div class=\\"d2h-file-side-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-files-diff">
<div class="d2h-file-side-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class=\\"d2h-info\\">
<div class=\\"d2h-code-side-line d2h-info\\">
<td class="d2h-info">
<div class="d2h-code-side-line">
File without changes
</div>
</td>
@ -384,10 +392,10 @@ describe('SideBySideRenderer', () => {
</table>
</div>
</div>
<div class=\\"d2h-file-side-diff\\">
<div class=\\"d2h-code-wrapper\\">
<table class=\\"d2h-diff-table\\">
<tbody class=\\"d2h-diff-tbody\\">
<div class="d2h-file-side-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
</tbody>
</table>
@ -398,6 +406,81 @@ describe('SideBySideRenderer', () => {
</div>"
`);
});
it('should work for too big file diff', () => {
const exampleJson = [
{
blocks: [
{
header: '<a href="http://example.com">Custom link to render</a>',
lines: [],
newStartLine: 0,
oldStartLine: 0,
oldStartLine2: undefined,
},
],
deletedLines: 0,
addedLines: 0,
oldName: 'sample',
language: 'js',
newName: 'sample',
isCombined: false,
isGitDiff: false,
isTooBig: true,
},
];
const hoganUtils = new HoganJsUtils({});
const sideBySideRenderer = new SideBySideRenderer(hoganUtils);
const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(`
"<div class="d2h-wrapper d2h-light-color-scheme">
<div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class="d2h-file-header">
<span class="d2h-file-name-wrapper">
<svg aria-hidden="true" class="d2h-icon" height="16" version="1.1" viewBox="0 0 12 16" width="12">
<path d="M6 5H2v-1h4v1zM2 8h7v-1H2v1z m0 2h7v-1H2v1z m0 2h7v-1H2v1z m10-7.5v9.5c0 0.55-0.45 1-1 1H1c-0.55 0-1-0.45-1-1V2c0-0.55 0.45-1 1-1h7.5l3.5 3.5z m-1 0.5L8 2H1v12h10V5z"></path>
</svg> <span class="d2h-file-name">sample</span>
<span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>
</div>
<div class="d2h-files-diff">
<div class="d2h-file-side-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class="d2h-code-side-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-side-line"><a href="http://example.com">Custom link to render</a></div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
<div class="d2h-file-side-diff">
<div class="d2h-code-wrapper">
<table class="d2h-diff-table">
<tbody class="d2h-diff-tbody">
<tr>
<td class="d2h-code-side-linenumber d2h-info"></td>
<td class="d2h-info">
<div class="d2h-code-side-line">&nbsp;</div>
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
</div>"
`);
});
});
describe('processLines', () => {
@ -425,26 +508,26 @@ describe('SideBySideRenderer', () => {
const html = sideBySideRenderer.processChangedLines(false, oldLines, newLines);
expect(html).toMatchInlineSnapshot(`
Object {
{
"left": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-del d2h-change\\">
<td class="d2h-code-side-linenumber d2h-del d2h-change">
1
</td>
<td class=\\"d2h-del d2h-change\\">
<div class=\\"d2h-code-side-line d2h-del d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span>
<td class="d2h-del d2h-change">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">-</span>
<span class="d2h-code-line-ctn"><del>test</del></span>
</div>
</td>
</tr>",
"right": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-ins d2h-change\\">
<td class="d2h-code-side-linenumber d2h-ins d2h-change">
1
</td>
<td class=\\"d2h-ins d2h-change\\">
<div class=\\"d2h-code-side-line d2h-ins d2h-change\\">
<span class=\\"d2h-code-line-prefix\\">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span>
<td class="d2h-ins d2h-change">
<div class="d2h-code-side-line">
<span class="d2h-code-line-prefix">+</span>
<span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div>
</td>
</tr>",

View file

@ -4,18 +4,18 @@ describe('Utils', () => {
describe('escapeForRegExp', () => {
it('should escape markdown link text', () => {
const result = escapeForRegExp('[Link](https://diff2html.xyz)');
expect(result).toEqual('\\[Link\\]\\(https:\\/\\/diff2html\\.xyz\\)');
expect(result).toBe('\\[Link\\]\\(https:\\/\\/diff2html\\.xyz\\)');
});
it('should escape all dangerous characters', () => {
const result = escapeForRegExp('-[]/{}()*+?.\\^$|');
expect(result).toEqual('\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|');
expect(result).toBe('\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|');
});
});
describe('unifyPath', () => {
it('should unify windows style path', () => {
const result = unifyPath('\\Users\\Downloads\\diff.html');
expect(result).toEqual('/Users/Downloads/diff.html');
expect(result).toBe('/Users/Downloads/diff.html');
});
});

View file

@ -4,6 +4,9 @@ import { escapeForRegExp } from './utils';
export interface DiffParserConfig {
srcPrefix?: string;
dstPrefix?: string;
diffMaxChanges?: number;
diffMaxLineLength?: number;
diffTooBigMessage?: (fileIndex: number) => string;
}
function getExtension(filename: string, language: string): string {
@ -182,12 +185,16 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
}
/* Create block metadata */
// eslint-disable-next-line
// @ts-ignore
currentBlock = {
lines: [],
// eslint-disable-next-line
// @ts-ignore
oldStartLine: oldLine,
// eslint-disable-next-line
// @ts-ignore
oldStartLine2: oldLine2,
// eslint-disable-next-line
// @ts-ignore
newStartLine: newLine,
header: line,
};
@ -265,11 +272,11 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
const nxtLine = diffLines[lineIndex + 1];
const afterNxtLine = diffLines[lineIndex + 2];
if (line.startsWith('diff')) {
if (line.startsWith('diff --git') || line.startsWith('diff --combined')) {
startFile();
// diff --git a/blocked_delta_results.png b/blocked_delta_results.png
const gitDiffStart = /^diff --git "?(.+)"? "?(.+)"?/;
const gitDiffStart = /^diff --git "?([a-ciow]\/.+)"? "?([a-ciow]\/.+)"?/;
if ((values = gitDiffStart.exec(line))) {
possibleOldName = getFilename(values[1], undefined, config.dstPrefix);
possibleNewName = getFilename(values[2], undefined, config.srcPrefix);
@ -283,11 +290,27 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
return;
}
if (line.startsWith('Binary files') && !currentFile?.isGitDiff) {
startFile();
const unixDiffBinaryStart = /^Binary files "?([a-ciow]\/.+)"? and "?([a-ciow]\/.+)"? differ/;
if ((values = unixDiffBinaryStart.exec(line))) {
possibleOldName = getFilename(values[1], undefined, config.dstPrefix);
possibleNewName = getFilename(values[2], undefined, config.srcPrefix);
}
if (currentFile === null) {
throw new Error('Where is my file !!!');
}
currentFile.isBinary = true;
return;
}
if (
!currentFile || // If we do not have a file yet, we should crete one
(!currentFile.isGitDiff &&
currentFile && // If we already have some file in progress and
line.startsWith(oldFileNameHeader) && // If we get to an old file path header line
currentFile && // If we already have some file in progress and
line.startsWith(oldFileNameHeader) && // If we get to an old file path header line
// And is followed by the new file path header line and the hunk header line
nxtLine.startsWith(newFileNameHeader) &&
afterNxtLine.startsWith(hunkHeaderPrefix))
@ -295,6 +318,31 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
startFile();
}
// Ignore remaining diff for current file if marked as too big
if (currentFile?.isTooBig) {
return;
}
if (
currentFile &&
((typeof config.diffMaxChanges === 'number' &&
currentFile.addedLines + currentFile.deletedLines > config.diffMaxChanges) ||
(typeof config.diffMaxLineLength === 'number' && line.length > config.diffMaxLineLength))
) {
currentFile.isTooBig = true;
currentFile.addedLines = 0;
currentFile.deletedLines = 0;
currentFile.blocks = [];
currentBlock = null;
const message =
typeof config.diffTooBigMessage === 'function'
? config.diffTooBigMessage(files.length)
: 'Diff too big to be displayed';
startBlock(message);
return;
}
/*
* We need to make sure that we have the three lines of the header.
* This avoids cases like the ones described in:
@ -410,18 +458,16 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
} else if ((values = index.exec(line))) {
currentFile.checksumBefore = values[1];
currentFile.checksumAfter = values[2];
values[3] && (currentFile.mode = values[3]);
if (values[3]) currentFile.mode = values[3];
} else if ((values = combinedIndex.exec(line))) {
currentFile.checksumBefore = [values[2], values[3]];
currentFile.checksumAfter = values[1];
} else if ((values = combinedMode.exec(line))) {
currentFile.oldMode = [values[2], values[3]];
currentFile.newMode = values[1];
// eslint-disable-next-line sonarjs/no-duplicated-branches
} else if ((values = combinedNewFile.exec(line))) {
currentFile.newFileMode = values[1];
currentFile.isNew = true;
// eslint-disable-next-line sonarjs/no-duplicated-branches
} else if ((values = combinedDeletedFile.exec(line))) {
currentFile.deletedFileMode = values[1];
currentFile.isDeleted = true;

View file

@ -1,5 +1,5 @@
import * as DiffParser from './diff-parser';
import * as fileListPrinter from './file-list-renderer';
import { FileListRenderer } from './file-list-renderer';
import LineByLineRenderer, { LineByLineRendererConfig, defaultLineByLineRendererConfig } from './line-by-line-renderer';
import SideBySideRenderer, { SideBySideRendererConfig, defaultSideBySideRendererConfig } from './side-by-side-renderer';
import { DiffFile, OutputFormatType } from './types';
@ -32,7 +32,10 @@ export function html(diffInput: string | DiffFile[], configuration: Diff2HtmlCon
const hoganUtils = new HoganJsUtils(config);
const fileList = config.drawFileList ? fileListPrinter.render(diffJson, hoganUtils) : '';
const { colorScheme } = config;
const fileListRendererConfig = { colorScheme };
const fileList = config.drawFileList ? new FileListRenderer(hoganUtils, fileListRendererConfig).render(diffJson) : '';
const diffOutput =
config.outputFormat === 'side-by-side'

View file

@ -1,33 +1,52 @@
import * as renderUtils from './render-utils';
import HoganJsUtils from './hoganjs-utils';
import { DiffFile } from './types';
import { ColorSchemeType, DiffFile } from './types';
const baseTemplatesPath = 'file-summary';
const iconsBaseTemplatesPath = 'icon';
export function render(diffFiles: DiffFile[], hoganUtils: HoganJsUtils): string {
const files = diffFiles
.map(file =>
hoganUtils.render(
baseTemplatesPath,
'line',
{
fileHtmlId: renderUtils.getHtmlId(file),
oldName: file.oldName,
newName: file.newName,
fileName: renderUtils.filenameDiff(file),
deletedLines: '-' + file.deletedLines,
addedLines: '+' + file.addedLines,
},
{
fileIcon: hoganUtils.template(iconsBaseTemplatesPath, renderUtils.getFileIcon(file)),
},
),
)
.join('\n');
return hoganUtils.render(baseTemplatesPath, 'wrapper', {
filesNumber: diffFiles.length,
files: files,
});
export interface FileListRendererConfig {
colorScheme?: ColorSchemeType;
}
export const defaultFileListRendererConfig = {
colorScheme: renderUtils.defaultRenderConfig.colorScheme,
};
export class FileListRenderer {
private readonly hoganUtils: HoganJsUtils;
private readonly config: typeof defaultFileListRendererConfig;
constructor(hoganUtils: HoganJsUtils, config: FileListRendererConfig = {}) {
this.hoganUtils = hoganUtils;
this.config = { ...defaultFileListRendererConfig, ...config };
}
render(diffFiles: DiffFile[]): string {
const files = diffFiles
.map(file =>
this.hoganUtils.render(
baseTemplatesPath,
'line',
{
fileHtmlId: renderUtils.getHtmlId(file),
oldName: file.oldName,
newName: file.newName,
fileName: renderUtils.filenameDiff(file),
deletedLines: '-' + file.deletedLines,
addedLines: '+' + file.addedLines,
},
{
fileIcon: this.hoganUtils.template(iconsBaseTemplatesPath, renderUtils.getFileIcon(file)),
},
),
)
.join('\n');
return this.hoganUtils.render(baseTemplatesPath, 'wrapper', {
colorScheme: renderUtils.colorSchemeToCss(this.config.colorScheme),
filesNumber: diffFiles.length,
files: files,
});
}
}

View file

@ -39,7 +39,7 @@ export default class HoganJsUtils {
try {
const template = this.preCompiledTemplates[templateKey];
return template.render(params, partials, indent);
} catch (e) {
} catch (_e) {
throw new Error(`Could not find template to render '${templateKey}'`);
}
}

View file

@ -52,7 +52,10 @@ export default class LineByLineRenderer {
})
.join('\n');
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', {
colorScheme: renderUtils.colorSchemeToCss(this.config.colorScheme),
content: diffsHtml,
});
}
makeFileDiffHtml(file: DiffFile, diffs: string): string {
@ -95,7 +98,7 @@ export default class LineByLineRenderer {
.map(block => {
let lines = this.hoganUtils.render(genericTemplatesPath, 'block-header', {
CSSLineClass: renderUtils.CSSLineClass,
blockHeader: block.header,
blockHeader: file.isTooBig ? block.header : renderUtils.escapeForHtml(block.header),
lineClass: 'd2h-code-linenumber',
contentClass: 'd2h-code-line',
});
@ -103,14 +106,14 @@ export default class LineByLineRenderer {
this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => {
if (oldLines.length && newLines.length && !contextLines.length) {
this.applyRematchMatching(oldLines, newLines, matcher).map(([oldLines, newLines]) => {
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
const { left, right } = this.processChangedLines(file, file.isCombined, oldLines, newLines);
lines += left;
lines += right;
});
} else if (contextLines.length) {
contextLines.forEach(line => {
const { prefix, content } = renderUtils.deconstructLine(line.content, file.isCombined);
lines += this.generateSingleLineHtml({
lines += this.generateSingleLineHtml(file, {
type: renderUtils.CSSLineClass.CONTEXT,
prefix: prefix,
content: content,
@ -119,7 +122,7 @@ export default class LineByLineRenderer {
});
});
} else if (oldLines.length || newLines.length) {
const { left, right } = this.processChangedLines(file.isCombined, oldLines, newLines);
const { left, right } = this.processChangedLines(file, file.isCombined, oldLines, newLines);
lines += left;
lines += right;
} else {
@ -188,7 +191,7 @@ export default class LineByLineRenderer {
return doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]];
}
processChangedLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
processChangedLines(file: DiffFile, isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
const fileHtml = {
right: '',
left: '',
@ -240,7 +243,7 @@ export default class LineByLineRenderer {
}
: undefined;
const { left, right } = this.generateLineHtml(preparedOldLine, preparedNewLine);
const { left, right } = this.generateLineHtml(file, preparedOldLine, preparedNewLine);
fileHtml.left += left;
fileHtml.right += right;
}
@ -248,14 +251,14 @@ export default class LineByLineRenderer {
return fileHtml;
}
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
generateLineHtml(file: DiffFile, oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
return {
left: this.generateSingleLineHtml(oldLine),
right: this.generateSingleLineHtml(newLine),
left: this.generateSingleLineHtml(file, oldLine),
right: this.generateSingleLineHtml(file, newLine),
};
}
generateSingleLineHtml(line?: DiffPreparedLine): string {
generateSingleLineHtml(file: DiffFile, line?: DiffPreparedLine): string {
if (line === undefined) return '';
const lineNumberHtml = this.hoganUtils.render(baseTemplatesPath, 'numbers', {
@ -270,6 +273,8 @@ export default class LineByLineRenderer {
prefix: line.prefix === ' ' ? '&nbsp;' : line.prefix,
content: line.content,
lineNumber: lineNumberHtml,
line,
file,
});
}
}

View file

@ -2,7 +2,15 @@ import * as jsDiff from 'diff';
import { unifyPath, hashCode } from './utils';
import * as rematch from './rematch';
import { LineMatchingType, DiffStyleType, LineType, DiffLineParts, DiffFile, DiffFileName } from './types';
import {
ColorSchemeType,
DiffFile,
DiffFileName,
DiffLineParts,
DiffStyleType,
LineMatchingType,
LineType,
} from './types';
export type CSSLineClass =
| 'd2h-ins'
@ -37,6 +45,7 @@ export interface RenderConfig {
matchWordsThreshold?: number;
maxLineLengthHighlight?: number;
diffStyle?: DiffStyleType;
colorScheme?: ColorSchemeType;
}
export const defaultRenderConfig = {
@ -44,6 +53,7 @@ export const defaultRenderConfig = {
matchWordsThreshold: 0.25,
maxLineLengthHighlight: 10000,
diffStyle: DiffStyleType.WORD,
colorScheme: ColorSchemeType.LIGHT,
};
const separator = '/';
@ -76,6 +86,18 @@ export function toCSSClass(lineType: LineType): CSSLineClass {
}
}
export function colorSchemeToCss(colorScheme: ColorSchemeType): string {
switch (colorScheme) {
case ColorSchemeType.DARK:
return 'd2h-dark-color-scheme';
case ColorSchemeType.AUTO:
return 'd2h-auto-color-scheme';
case ColorSchemeType.LIGHT:
default:
return 'd2h-light-color-scheme';
}
}
/**
* Prefix length of the hunk lines in the diff
*/
@ -186,9 +208,7 @@ export function filenameDiff(file: DiffFileName): string {
* Generates a unique string numerical identifier based on the names of the file diff
*/
export function getHtmlId(file: DiffFileName): string {
return `d2h-${hashCode(filenameDiff(file))
.toString()
.slice(-6)}`;
return `d2h-${hashCode(filenameDiff(file)).toString().slice(-6)}`;
}
/**
@ -231,11 +251,11 @@ export function diffHighlight(
return {
oldLine: {
prefix: line1.prefix,
content: line1.content,
content: escapeForHtml(line1.content),
},
newLine: {
prefix: line2.prefix,
content: line2.content,
content: escapeForHtml(line2.content),
},
};
}

View file

@ -52,7 +52,10 @@ export default class SideBySideRenderer {
})
.join('\n');
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', {
colorScheme: renderUtils.colorSchemeToCss(this.config.colorScheme),
content: diffsHtml,
});
}
makeFileDiffHtml(file: DiffFile, diffs: FileHtml): string {
@ -97,7 +100,7 @@ export default class SideBySideRenderer {
return file.blocks
.map(block => {
const fileHtml = {
left: this.makeHeaderHtml(block.header),
left: this.makeHeaderHtml(block.header, file),
right: this.makeHeaderHtml(''),
};
@ -203,10 +206,10 @@ export default class SideBySideRenderer {
return doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]];
}
makeHeaderHtml(blockHeader: string): string {
makeHeaderHtml(blockHeader: string, file?: DiffFile): string {
return this.hoganUtils.render(genericTemplatesPath, 'block-header', {
CSSLineClass: renderUtils.CSSLineClass,
blockHeader: blockHeader,
blockHeader: file?.isTooBig ? blockHeader : renderUtils.escapeForHtml(blockHeader),
lineClass: 'd2h-code-side-linenumber',
contentClass: 'd2h-code-side-line',
});
@ -285,8 +288,8 @@ export default class SideBySideRenderer {
type: line?.type || `${renderUtils.CSSLineClass.CONTEXT} d2h-emptyplaceholder`,
lineClass: line !== undefined ? lineClass : `${lineClass} d2h-code-side-emptyplaceholder`,
contentClass: line !== undefined ? contentClass : `${contentClass} d2h-code-side-emptyplaceholder`,
prefix: line?.prefix === ' ' ? '&nbsp;' : line?.prefix || '&nbsp;',
content: line?.content || '&nbsp;',
prefix: line?.prefix === ' ' ? '&nbsp;' : line?.prefix,
content: line?.content,
lineNumber: line?.number,
});
}

View file

@ -1,4 +1,4 @@
<div class="d2h-file-list-wrapper">
<div class="d2h-file-list-wrapper {{colorScheme}}">
<div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed ({{filesNumber}})</span>
<a class="d2h-file-switch d2h-hide">hide</a>

View file

@ -1,6 +1,6 @@
<tr>
<td class="{{lineClass}} {{CSSLineClass.INFO}}"></td>
<td class="{{CSSLineClass.INFO}}">
<div class="{{contentClass}} {{CSSLineClass.INFO}}">{{{blockHeader}}}</div>
<div class="{{contentClass}}">{{#blockHeader}}{{{blockHeader}}}{{/blockHeader}}{{^blockHeader}}&nbsp;{{/blockHeader}}</div>
</td>
</tr>

View file

@ -1,6 +1,6 @@
<tr>
<td class="{{CSSLineClass.INFO}}">
<div class="{{contentClass}} {{CSSLineClass.INFO}}">
<div class="{{contentClass}}">
File without changes
</div>
</td>

View file

@ -3,3 +3,7 @@
<span class="d2h-file-name">{{fileDiffName}}</span>
{{>fileTag}}
</span>
<label class="d2h-file-collapse">
<input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed
</label>

View file

@ -3,13 +3,19 @@
{{{lineNumber}}}
</td>
<td class="{{type}}">
<div class="{{contentClass}} {{type}}">
<div class="{{contentClass}}">
{{#prefix}}
<span class="d2h-code-line-prefix">{{{prefix}}}</span>
{{/prefix}}
{{^prefix}}
<span class="d2h-code-line-prefix">&nbsp;</span>
{{/prefix}}
{{#content}}
<span class="d2h-code-line-ctn">{{{content}}}</span>
{{/content}}
{{^content}}
<span class="d2h-code-line-ctn"><br></span>
{{/content}}
</div>
</td>
</tr>

View file

@ -1,3 +1,3 @@
<div class="d2h-wrapper">
<div class="d2h-wrapper {{colorScheme}}">
{{{content}}}
</div>

View file

@ -62,6 +62,7 @@ export interface DiffFile extends DiffFileName {
isCopy?: boolean;
isRename?: boolean;
isBinary?: boolean;
isTooBig?: boolean;
unchangedPercentage?: number;
changedPercentage?: number;
checksumBefore?: string | string[];
@ -90,3 +91,9 @@ export const DiffStyleType: { [_: string]: DiffStyleType } = {
WORD: 'word',
CHAR: 'char',
};
export enum ColorSchemeType {
AUTO = 'auto',
DARK = 'dark',
LIGHT = 'light',
}

View file

@ -5,15 +5,99 @@
*
*/
:root,
:host {
--d2h-bg-color: #fff;
--d2h-border-color: #ddd;
--d2h-dim-color: rgba(0, 0, 0, 0.3);
--d2h-line-border-color: #eeeeee;
--d2h-file-header-bg-color: #f7f7f7;
--d2h-file-header-border-color: #d8d8d8;
--d2h-empty-placeholder-bg-color: #f1f1f1;
--d2h-empty-placeholder-border-color: #e1e1e1;
--d2h-selected-color: #c8e1ff;
--d2h-ins-bg-color: #dfd;
--d2h-ins-border-color: #b4e2b4;
--d2h-ins-highlight-bg-color: #97f295;
--d2h-ins-label-color: #399839;
--d2h-del-bg-color: #fee8e9;
--d2h-del-border-color: #e9aeae;
--d2h-del-highlight-bg-color: #ffb6ba;
--d2h-del-label-color: #c33;
--d2h-change-del-color: #fdf2d0;
--d2h-change-ins-color: #ded;
--d2h-info-bg-color: #f8fafd;
--d2h-info-border-color: #d5e4f2;
--d2h-change-label-color: #d0b44c;
--d2h-moved-label-color: #3572b0;
/**
* Dark Color Scheme
*/
--d2h-dark-color: rgb(230, 237, 243);
--d2h-dark-bg-color: rgb(13, 17, 23);
--d2h-dark-border-color: rgb(48, 54, 61);
--d2h-dark-dim-color: rgb(110, 118, 129);
--d2h-dark-line-border-color: rgb(33, 38, 45);
--d2h-dark-file-header-bg-color: rgb(22, 27, 34);
--d2h-dark-file-header-border-color: rgb(48, 54, 61);
--d2h-dark-empty-placeholder-bg-color: rgba(110, 118, 129, 0.1);
--d2h-dark-empty-placeholder-border-color: rgb(48, 54, 61);
--d2h-dark-selected-color: rgba(56, 139, 253, 0.1);
--d2h-dark-ins-bg-color: rgba(46, 160, 67, 0.15);
--d2h-dark-ins-border-color: rgba(46, 160, 67, 0.4);
--d2h-dark-ins-highlight-bg-color: rgba(46, 160, 67, 0.4);
--d2h-dark-ins-label-color: rgb(63, 185, 80);
--d2h-dark-del-bg-color: rgba(248, 81, 73, 0.1);
--d2h-dark-del-border-color: rgba(248, 81, 73, 0.4);
--d2h-dark-del-highlight-bg-color: rgba(248, 81, 73, 0.4);
--d2h-dark-del-label-color: rgb(248, 81, 73);
--d2h-dark-change-del-color: rgba(210, 153, 34, 0.2);
--d2h-dark-change-ins-color: rgba(46, 160, 67, 0.25);
--d2h-dark-info-bg-color: rgba(56, 139, 253, 0.1);
--d2h-dark-info-border-color: rgba(56, 139, 253, 0.4);
--d2h-dark-change-label-color: rgb(210, 153, 34);
--d2h-dark-moved-label-color: #3572b0;
}
.d2h-wrapper {
text-align: left;
}
.d2h-file-header {
display: flex;
height: 35px;
padding: 5px 10px;
border-bottom: 1px solid #d8d8d8;
background-color: #f7f7f7;
border-bottom: 1px solid var(--d2h-file-header-border-color);
background-color: var(--d2h-file-header-bg-color);
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
}
.d2h-file-header.d2h-sticky-header {
position: sticky;
top: 0;
z-index: 1;
}
.d2h-file-stats {
@ -26,18 +110,18 @@
.d2h-lines-added {
text-align: right;
border: 1px solid #b4e2b4;
border: 1px solid var(--d2h-ins-border-color);
border-radius: 5px 0 0 5px;
color: #399839;
color: var(--d2h-ins-label-color);
padding: 2px;
vertical-align: middle;
}
.d2h-lines-deleted {
text-align: left;
border: 1px solid #e9aeae;
border: 1px solid var(--d2h-del-border-color);
border-radius: 0 5px 5px 0;
color: #c33;
color: var(--d2h-del-label-color);
padding: 2px;
vertical-align: middle;
margin-left: 1px;
@ -51,7 +135,6 @@
-ms-flex-align: center;
align-items: center;
width: 100%;
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
font-size: 15px;
}
@ -62,11 +145,30 @@
}
.d2h-file-wrapper {
border: 1px solid #ddd;
border: 1px solid var(--d2h-border-color);
border-radius: 3px;
margin-bottom: 1em;
}
.d2h-file-collapse {
justify-content: flex-end;
display: none;
cursor: pointer;
font-size: 12px;
align-items: center;
border-radius: 3px;
border: 1px solid var(--d2h-border-color);
padding: 4px 8px;
}
.d2h-file-collapse.d2h-selected {
background-color: var(--d2h-selected-color);
}
.d2h-file-collapse-input {
margin: 0 4px 0 0;
}
.d2h-diff-table {
width: 100%;
border-collapse: collapse;
@ -75,27 +177,31 @@
}
.d2h-files-diff {
display: block;
display: flex;
width: 100%;
height: 100%;
}
.d2h-file-diff {
overflow-y: hidden;
}
.d2h-files-diff.d2h-d-none,
.d2h-file-diff.d2h-d-none {
display: none;
}
.d2h-file-side-diff {
display: inline-block;
overflow-x: scroll;
overflow-y: hidden;
width: 50%;
margin-right: -4px;
margin-bottom: -8px;
}
.d2h-code-line {
display: inline-block;
white-space: nowrap;
user-select: none;
width: calc(100% - 16em);
/* Compensate for the absolute positioning of the line numbers */
padding: 0 8em;
}
@ -103,16 +209,29 @@
.d2h-code-side-line {
display: inline-block;
white-space: nowrap;
user-select: none;
width: calc(100% - 9em);
/* Compensate for the absolute positioning of the line numbers */
padding: 0 4.5em;
}
.d2h-code-line-ctn {
display: inline-block;
background: none;
padding: 0;
word-wrap: normal;
white-space: pre;
user-select: text;
width: 100%;
vertical-align: middle;
}
.d2h-code-line del,
.d2h-code-side-line del {
display: inline-block;
margin-top: -1px;
text-decoration: none;
background-color: #ffb6ba;
background-color: var(--d2h-del-highlight-bg-color);
border-radius: 0.2em;
}
@ -121,7 +240,7 @@
display: inline-block;
margin-top: -1px;
text-decoration: none;
background-color: #97f295;
background-color: var(--d2h-ins-highlight-bg-color);
border-radius: 0.2em;
text-align: left;
}
@ -134,14 +253,6 @@
white-space: pre;
}
.d2h-code-line-ctn {
display: inline;
background: none;
padding: 0;
word-wrap: normal;
white-space: pre;
}
.line-num1 {
box-sizing: border-box;
float: left;
@ -166,10 +277,10 @@
/* Keep the numbers fixed on line contents scroll */
position: absolute;
display: inline-block;
background-color: #fff;
color: rgba(0, 0, 0, 0.3);
background-color: var(--d2h-bg-color);
color: var(--d2h-dim-color);
text-align: right;
border: solid #eeeeee;
border: solid var(--d2h-line-border-color);
border-width: 0 1px 0 1px;
cursor: pointer;
}
@ -184,14 +295,15 @@
display: inline-block;
box-sizing: border-box;
width: 4em;
background-color: #fff;
color: rgba(0, 0, 0, 0.3);
background-color: var(--d2h-bg-color);
color: var(--d2h-dim-color);
text-align: right;
border: solid #eeeeee;
border: solid var(--d2h-line-border-color);
border-width: 0 1px 0 1px;
cursor: pointer;
overflow: hidden;
text-overflow: ellipsis;
padding: 0 0.5em 0 0.5em;
}
.d2h-code-side-linenumber:after {
@ -200,8 +312,20 @@
.d2h-code-side-emptyplaceholder,
.d2h-emptyplaceholder {
background-color: #f1f1f1;
border-color: #e1e1e1;
background-color: var(--d2h-empty-placeholder-bg-color);
border-color: var(--d2h-empty-placeholder-border-color);
}
.d2h-code-linenumber,
.d2h-code-side-linenumber,
.d2h-code-line-prefix,
.d2h-emptyplaceholder {
user-select: none;
}
.d2h-code-linenumber,
.d2h-code-side-linenumber {
direction: rtl;
}
/*
@ -209,27 +333,27 @@
*/
.d2h-del {
background-color: #fee8e9;
border-color: #e9aeae;
background-color: var(--d2h-del-bg-color);
border-color: var(--d2h-del-border-color);
}
.d2h-ins {
background-color: #dfd;
border-color: #b4e2b4;
background-color: var(--d2h-ins-bg-color);
border-color: var(--d2h-ins-border-color);
}
.d2h-info {
background-color: #f8fafd;
color: rgba(0, 0, 0, 0.3);
border-color: #d5e4f2;
background-color: var(--d2h-info-bg-color);
color: var(--d2h-dim-color);
border-color: var(--d2h-info-border-color);
}
.d2h-file-diff .d2h-del.d2h-change {
background-color: #fdf2d0;
background-color: var(--d2h-change-del-color);
}
.d2h-file-diff .d2h-ins.d2h-change {
background-color: #ded;
background-color: var(--d2h-change-ins-color);
}
/*
@ -242,11 +366,11 @@
.d2h-file-list-wrapper a {
text-decoration: none;
color: #3572b0;
color: var(--d2h-moved-label-color);
}
.d2h-file-list-wrapper a:visited {
color: #3572b0;
color: var(--d2h-moved-label-color);
}
.d2h-file-list-header {
@ -272,7 +396,7 @@
}
.d2h-file-list > li {
border-bottom: #ddd solid 1px;
border-bottom: var(--d2h-border-color) solid 1px;
padding: 5px 10px;
margin: 0;
}
@ -294,19 +418,19 @@
}
.d2h-deleted {
color: #c33;
color: var(--d2h-del-label-color);
}
.d2h-added {
color: #399839;
color: var(--d2h-ins-label-color);
}
.d2h-changed {
color: #d0b44c;
color: var(--d2h-change-label-color);
}
.d2h-moved {
color: #3572b0;
color: var(--d2h-moved-label-color);
}
.d2h-tag {
@ -316,60 +440,302 @@
font-size: 10px;
margin-left: 5px;
padding: 0 2px;
background-color: #fff;
background-color: var(--d2h-bg-color);
}
.d2h-deleted-tag {
border: #c33 1px solid;
border: var(--d2h-del-label-color) 1px solid;
}
.d2h-added-tag {
border: #399839 1px solid;
border: var(--d2h-ins-label-color) 1px solid;
}
.d2h-changed-tag {
border: #d0b44c 1px solid;
border: var(--d2h-change-label-color) 1px solid;
}
.d2h-moved-tag {
border: #3572b0 1px solid;
border: var(--d2h-moved-label-color) 1px solid;
}
/*
* Selection util.
/**
* Dark Mode Colors
*/
.selecting-left .d2h-code-line,
.selecting-left .d2h-code-line *,
.selecting-right td.d2h-code-linenumber,
.selecting-right td.d2h-code-linenumber *,
.selecting-left .d2h-code-side-line,
.selecting-left .d2h-code-side-line *,
.selecting-right td.d2h-code-side-linenumber,
.selecting-right td.d2h-code-side-linenumber * {
-webkit-touch-callout: none;
-webkit-user-select: none;
-moz-user-select: none;
-ms-user-select: none;
user-select: none;
.d2h-dark-color-scheme {
color: var(--d2h-dark-color);
background-color: var(--d2h-dark-bg-color);
}
.selecting-left .d2h-code-line::-moz-selection,
.selecting-left .d2h-code-line *::-moz-selection,
.selecting-right td.d2h-code-linenumber::-moz-selection,
.selecting-left .d2h-code-side-line::-moz-selection,
.selecting-left .d2h-code-side-line *::-moz-selection,
.selecting-right td.d2h-code-side-linenumber::-moz-selection,
.selecting-right td.d2h-code-side-linenumber *::-moz-selection {
background: transparent;
.d2h-dark-color-scheme .d2h-file-header {
background-color: var(--d2h-dark-file-header-bg-color);
border-bottom: var(--d2h-dark-file-header-border-color);
}
.selecting-left .d2h-code-line::selection,
.selecting-left .d2h-code-line *::selection,
.selecting-right td.d2h-code-linenumber::selection,
.selecting-left .d2h-code-side-line::selection,
.selecting-left .d2h-code-side-line *::selection,
.selecting-right td.d2h-code-side-linenumber::selection,
.selecting-right td.d2h-code-side-linenumber *::selection {
background: transparent;
.d2h-dark-color-scheme .d2h-lines-added {
border: 1px solid var(--d2h-dark-ins-border-color);
color: var(--d2h-dark-ins-label-color);
}
.d2h-dark-color-scheme .d2h-lines-deleted {
border: 1px solid var(--d2h-dark-del-border-color);
color: var(--d2h-dark-del-label-color);
}
.d2h-dark-color-scheme .d2h-code-line del,
.d2h-dark-color-scheme .d2h-code-side-line del {
background-color: var(--d2h-dark-del-highlight-bg-color);
}
.d2h-dark-color-scheme .d2h-code-line ins,
.d2h-dark-color-scheme .d2h-code-side-line ins {
background-color: var(--d2h-dark-ins-highlight-bg-color);
}
.d2h-dark-color-scheme .d2h-diff-tbody {
border-color: var(--d2h-dark-border-color);
}
.d2h-dark-color-scheme .d2h-code-side-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-dark-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,
.d2h-dark-color-scheme .d2h-files-diff .d2h-emptyplaceholder {
background-color: var(--d2h-dark-empty-placeholder-bg-color);
border-color: var(--d2h-dark-empty-placeholder-border-color);
}
.d2h-dark-color-scheme .d2h-code-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-dark-color-scheme .d2h-del {
background-color: var(--d2h-dark-del-bg-color);
border-color: var(--d2h-dark-del-border-color);
}
.d2h-dark-color-scheme .d2h-ins {
background-color: var(--d2h-dark-ins-bg-color);
border-color: var(--d2h-dark-ins-border-color);
}
.d2h-dark-color-scheme .d2h-info {
background-color: var(--d2h-dark-info-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-info-border-color);
}
.d2h-dark-color-scheme .d2h-file-diff .d2h-del.d2h-change {
background-color: var(--d2h-dark-change-del-color);
}
.d2h-dark-color-scheme .d2h-file-diff .d2h-ins.d2h-change {
background-color: var(--d2h-dark-change-ins-color);
}
.d2h-dark-color-scheme .d2h-file-wrapper {
border: 1px solid var(--d2h-dark-border-color);
}
.d2h-dark-color-scheme .d2h-file-collapse {
border: 1px solid var(--d2h-dark-bg-color);
}
.d2h-dark-color-scheme .d2h-file-collapse.d2h-selected {
background-color: var(--d2h-dark-selected-color);
}
.d2h-dark-color-scheme .d2h-file-list-wrapper a {
color: var(--d2h-dark-moved-label-color);
}
.d2h-dark-color-scheme .d2h-file-list-wrapper a:visited {
color: var(--d2h-dark-moved-label-color);
}
.d2h-dark-color-scheme .d2h-file-list > li {
border-bottom: var(--d2h-dark-bg-color) solid 1px;
}
.d2h-dark-color-scheme .d2h-deleted {
color: var(--d2h-dark-del-label-color);
}
.d2h-dark-color-scheme .d2h-added {
color: var(--d2h-dark-ins-label-color);
}
.d2h-dark-color-scheme .d2h-changed {
color: var(--d2h-dark-change-label-color);
}
.d2h-dark-color-scheme .d2h-moved {
color: var(--d2h-dark-moved-label-color);
}
.d2h-dark-color-scheme .d2h-tag {
background-color: var(--d2h-dark-bg-color);
}
.d2h-dark-color-scheme .d2h-deleted-tag {
border: var(--d2h-dark-del-label-color) 1px solid;
}
.d2h-dark-color-scheme .d2h-added-tag {
border: var(--d2h-dark-ins-label-color) 1px solid;
}
.d2h-dark-color-scheme .d2h-changed-tag {
border: var(--d2h-dark-change-label-color) 1px solid;
}
.d2h-dark-color-scheme .d2h-moved-tag {
border: var(--d2h-dark-moved-label-color) 1px solid;
}
/**
* Auto Mode Colors
*/
@media (prefers-color-scheme: dark) {
.d2h-auto-color-scheme {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-color);
}
.d2h-auto-color-scheme .d2h-file-header {
background-color: var(--d2h-dark-file-header-bg-color);
border-bottom: var(--d2h-dark-file-header-border-color);
}
.d2h-auto-color-scheme .d2h-lines-added {
border: 1px solid var(--d2h-dark-ins-border-color);
color: var(--d2h-dark-ins-label-color);
}
.d2h-auto-color-scheme .d2h-lines-deleted {
border: 1px solid var(--d2h-dark-del-border-color);
color: var(--d2h-dark-del-label-color);
}
.d2h-auto-color-scheme .d2h-code-line del,
.d2h-auto-color-scheme .d2h-code-side-line del {
background-color: var(--d2h-dark-del-highlight-bg-color);
}
.d2h-auto-color-scheme .d2h-code-line ins,
.d2h-auto-color-scheme .d2h-code-side-line ins {
background-color: var(--d2h-dark-ins-highlight-bg-color);
}
.d2h-auto-color-scheme .d2h-diff-tbody {
border-color: var(--d2h-dark-border-color);
}
.d2h-auto-color-scheme .d2h-code-side-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-auto-color-scheme .d2h-files-diff .d2h-code-side-emptyplaceholder,
.d2h-auto-color-scheme .d2h-files-diff .d2h-emptyplaceholder {
background-color: var(--d2h-dark-empty-placeholder-bg-color);
border-color: var(--d2h-dark-empty-placeholder-border-color);
}
.d2h-auto-color-scheme .d2h-code-linenumber {
background-color: var(--d2h-dark-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-line-border-color);
}
.d2h-auto-color-scheme .d2h-del {
background-color: var(--d2h-dark-del-bg-color);
border-color: var(--d2h-dark-del-border-color);
}
.d2h-auto-color-scheme .d2h-ins {
background-color: var(--d2h-dark-ins-bg-color);
border-color: var(--d2h-dark-ins-border-color);
}
.d2h-auto-color-scheme .d2h-info {
background-color: var(--d2h-dark-info-bg-color);
color: var(--d2h-dark-dim-color);
border-color: var(--d2h-dark-info-border-color);
}
.d2h-auto-color-scheme .d2h-file-diff .d2h-del.d2h-change {
background-color: var(--d2h-dark-change-del-color);
}
.d2h-auto-color-scheme .d2h-file-diff .d2h-ins.d2h-change {
background-color: var(--d2h-dark-change-ins-color);
}
.d2h-auto-color-scheme .d2h-file-wrapper {
border: 1px solid var(--d2h-dark-border-color);
}
.d2h-auto-color-scheme .d2h-file-collapse {
border: 1px solid var(--d2h-dark-bg-color);
}
.d2h-auto-color-scheme .d2h-file-collapse.d2h-selected {
background-color: var(--d2h-dark-selected-color);
}
.d2h-auto-color-scheme .d2h-file-list-wrapper a {
color: var(--d2h-dark-moved-label-color);
}
.d2h-auto-color-scheme .d2h-file-list-wrapper a:visited {
color: var(--d2h-dark-moved-label-color);
}
.d2h-auto-color-scheme .d2h-file-list > li {
border-bottom: var(--d2h-dark-bg-color) solid 1px;
}
.d2h-dark-color-scheme .d2h-deleted {
color: var(--d2h-dark-del-label-color);
}
.d2h-auto-color-scheme .d2h-added {
color: var(--d2h-dark-ins-label-color);
}
.d2h-auto-color-scheme .d2h-changed {
color: var(--d2h-dark-change-label-color);
}
.d2h-auto-color-scheme .d2h-moved {
color: var(--d2h-dark-moved-label-color);
}
.d2h-auto-color-scheme .d2h-tag {
background-color: var(--d2h-dark-bg-color);
}
.d2h-auto-color-scheme .d2h-deleted-tag {
border: var(--d2h-dark-del-label-color) 1px solid;
}
.d2h-auto-color-scheme .d2h-added-tag {
border: var(--d2h-dark-ins-label-color) 1px solid;
}
.d2h-auto-color-scheme .d2h-changed-tag {
border: var(--d2h-dark-change-label-color) 1px solid;
}
.d2h-auto-color-scheme .d2h-moved-tag {
border: var(--d2h-dark-moved-label-color) 1px solid;
}
}

View file

@ -1,16 +1,22 @@
import * as HighlightJS from 'highlight.js/lib/highlight.js';
import { ICompiledMode, IHighlightResult, IAutoHighlightResult } from 'highlight.js';
import { nodeStream, mergeStreams } from './highlight.js-helpers';
import { closeTags, nodeStream, mergeStreams, getLanguage } from './highlight.js-helpers';
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from '../../diff2html';
import { DiffFile } from '../../types';
import { HighlightResult, HLJSApi } from 'highlight.js';
export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
synchronisedScroll?: boolean;
highlight?: boolean;
fileListToggle?: boolean;
fileListStartVisible?: boolean;
highlightLanguages?: Map<string, string>;
/**
* @deprecated since version 3.1.0
* Smart selection is now enabled by default with vanilla CSS
*/
smartSelection?: boolean;
fileContentToggle?: boolean;
stickyFileHeaders?: boolean;
}
export const defaultDiff2HtmlUIConfig = {
@ -19,23 +25,25 @@ export const defaultDiff2HtmlUIConfig = {
highlight: true,
fileListToggle: true,
fileListStartVisible: false,
highlightLanguages: new Map<string, string>(),
/**
* @deprecated since version 3.1.0
* Smart selection is now enabled by default with vanilla CSS
*/
smartSelection: true,
fileContentToggle: true,
stickyFileHeaders: true,
};
export class Diff2HtmlUI {
readonly config: typeof defaultDiff2HtmlUIConfig;
readonly diffHtml: string;
readonly targetElement: HTMLElement;
readonly hljs: typeof HighlightJS | null = null;
readonly hljs: HLJSApi | null = null;
currentSelectionColumnId = -1;
constructor(
target: HTMLElement,
diffInput?: string | DiffFile[],
config: Diff2HtmlUIConfig = {},
hljs?: typeof HighlightJS,
) {
constructor(target: HTMLElement, diffInput?: string | DiffFile[], config: Diff2HtmlUIConfig = {}, hljs?: HLJSApi) {
this.config = { ...defaultDiff2HtmlUIConfig, ...config };
this.diffHtml = diffInput !== undefined ? html(diffInput, this.config) : target.innerHTML;
this.targetElement = target;
@ -44,10 +52,11 @@ export class Diff2HtmlUI {
draw(): void {
this.targetElement.innerHTML = this.diffHtml;
if (this.config.smartSelection) this.smartSelection();
if (this.config.synchronisedScroll) this.synchronisedScroll();
if (this.config.highlight) this.highlightCode();
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
if (this.config.fileContentToggle) this.fileContentToggle();
if (this.config.stickyFileHeaders) this.stickyFileHeaders();
}
synchronisedScroll(): void {
@ -73,7 +82,7 @@ export class Diff2HtmlUI {
}
fileListToggle(startVisible: boolean): void {
const showBtn: HTMLElement | null = this.targetElement.querySelector('d2h-show');
const showBtn: HTMLElement | null = this.targetElement.querySelector('.d2h-show');
const hideBtn: HTMLElement | null = this.targetElement.querySelector('.d2h-hide');
const fileList: HTMLElement | null = this.targetElement.querySelector('.d2h-file-list');
@ -101,46 +110,73 @@ export class Diff2HtmlUI {
else hide();
}
fileContentToggle(): void {
this.targetElement.querySelectorAll<HTMLElement>('.d2h-file-collapse').forEach(fileContentToggleBtn => {
fileContentToggleBtn.style.display = 'flex';
const toggleFileContents: (selector: string) => void = selector => {
const fileContents: HTMLElement | null | undefined = fileContentToggleBtn
.closest('.d2h-file-wrapper')
?.querySelector(selector);
if (fileContents !== null && fileContents !== undefined) {
fileContentToggleBtn.classList.toggle('d2h-selected');
fileContents.classList.toggle('d2h-d-none');
}
};
const toggleHandler: (e: Event) => void = e => {
if (fileContentToggleBtn === e.target) return;
toggleFileContents('.d2h-file-diff');
toggleFileContents('.d2h-files-diff');
};
fileContentToggleBtn.addEventListener('click', e => toggleHandler(e));
});
}
highlightCode(): void {
if (this.hljs === null) {
const hljs = this.hljs;
if (hljs === null) {
throw new Error('Missing a `highlight.js` implementation. Please provide one when instantiating Diff2HtmlUI.');
}
// Collect all the diff files and execute the highlight on their lines
const files = this.targetElement.querySelectorAll('.d2h-file-wrapper');
files.forEach(file => {
let oldLinesState: ICompiledMode;
let newLinesState: ICompiledMode;
const language = file.getAttribute('data-lang');
if (!(this.config.highlightLanguages instanceof Map)) {
this.config.highlightLanguages = new Map(Object.entries(this.config.highlightLanguages));
}
let hljsLanguage =
language && this.config.highlightLanguages.has(language)
? this.config.highlightLanguages.get(language)!
: language
? getLanguage(language)
: 'plaintext';
// Fallback to plaintext in case language is not loaded
if (hljs.getLanguage(hljsLanguage) === undefined) {
hljsLanguage = 'plaintext';
}
// Collect all the code lines and execute the highlight on them
const codeLines = file.querySelectorAll('.d2h-code-line-ctn');
codeLines.forEach(line => {
// HACK: help Typescript know that `this.hljs` is defined since we already checked it
if (this.hljs === null) return;
const text = line.textContent;
const lineParent = line.parentNode;
if (text === null || lineParent === null || !this.isElement(lineParent)) return;
const lineState = lineParent.classList.contains('d2h-del') ? oldLinesState : newLinesState;
const language = file.getAttribute('data-lang');
const result =
language && this.hljs.getLanguage(language)
? this.hljs.highlight(language, text, true, lineState)
: this.hljs.highlightAuto(text);
if (this.instanceOfIHighlightResult(result)) {
if (lineParent.classList.contains('d2h-del')) {
oldLinesState = result.top;
} else if (lineParent.classList.contains('d2h-ins')) {
newLinesState = result.top;
} else {
oldLinesState = result.top;
newLinesState = result.top;
}
}
const result: HighlightResult = closeTags(
hljs.highlight(text, {
language: hljsLanguage,
ignoreIllegals: true,
}),
);
const originalStream = nodeStream(line);
if (originalStream.length) {
@ -150,48 +186,25 @@ export class Diff2HtmlUI {
}
line.classList.add('hljs');
line.classList.add(result.language);
if (result.language) {
line.classList.add(result.language);
}
line.innerHTML = result.value;
});
});
}
smartSelection(): void {
const body = document.getElementsByTagName('body')[0];
const diffTable = body.getElementsByClassName('d2h-diff-table')[0];
diffTable.addEventListener('mousedown', event => {
if (event === null || !this.isElement(event.target)) return;
const table = event.target.closest('.d2h-diff-table');
if (table !== null) {
if (event.target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
table.classList.remove('selecting-left');
table.classList.add('selecting-right');
this.currentSelectionColumnId = 1;
} else if (event.target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
table.classList.remove('selecting-right');
table.classList.add('selecting-left');
this.currentSelectionColumnId = 0;
}
}
});
diffTable.addEventListener('copy', event => {
if (!this.isClipboardEvent(event)) return;
const clipboardData = event.clipboardData;
const text = this.getSelectedText();
if (clipboardData === null || text === undefined) return;
clipboardData.setData('text', text);
event.preventDefault();
stickyFileHeaders(): void {
this.targetElement.querySelectorAll('.d2h-file-header').forEach(header => {
header.classList.add('d2h-sticky-header');
});
}
private instanceOfIHighlightResult(object: IHighlightResult | IAutoHighlightResult): object is IHighlightResult {
return 'top' in object;
/**
* @deprecated since version 3.1.0
*/
smartSelection(): void {
console.warn('Smart selection is now enabled by default with CSS. No need to call this method anymore.');
}
private getHashTag(): string | null {
@ -206,37 +219,7 @@ export class Diff2HtmlUI {
return hashTag;
}
private getSelectedText(): string | undefined {
const sel = window.getSelection();
if (sel === null) return;
const range = sel.getRangeAt(0);
const doc = range.cloneContents();
const nodes = doc.querySelectorAll('tr');
const idx = this.currentSelectionColumnId;
let text = '';
if (nodes.length === 0) {
text = doc.textContent || '';
} else {
nodes.forEach((tr, i) => {
const td = tr.cells[tr.cells.length === 1 ? 0 : idx];
if (td === undefined || td.textContent === null) return;
text += (i ? '\n' : '') + td.textContent.replace(/\r\n|\r|\n/g, '');
});
}
return text;
}
private isElement(arg?: unknown): arg is Element {
return arg !== null && (arg as Element)?.classList !== undefined;
}
private isClipboardEvent(arg?: unknown): arg is ClipboardEvent {
return arg !== null && (arg as ClipboardEvent)?.clipboardData !== undefined;
}
}

View file

@ -9,4 +9,5 @@ export class Diff2HtmlUI extends Diff2HtmlUIBase {
}
}
export { Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig };
export { defaultDiff2HtmlUIConfig };
export type { Diff2HtmlUIConfig };

View file

@ -9,4 +9,5 @@ export class Diff2HtmlUI extends Diff2HtmlUIBase {
}
}
export { Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig };
export { defaultDiff2HtmlUIConfig };
export type { Diff2HtmlUIConfig };

View file

@ -3,13 +3,12 @@
* Used to highlight selected html elements using context
*/
import { HighlightResult } from 'highlight.js';
/* Utility functions */
function escape(value: string): string {
return value
.replace(/&/gm, '&amp;')
.replace(/</gm, '&lt;')
.replace(/>/gm, '&gt;');
function escapeHTML(value: string): string {
return value.replace(/&/gm, '&amp;').replace(/</gm, '&lt;').replace(/>/gm, '&gt;');
}
function tag(node: Node): string {
@ -97,7 +96,7 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
}
result += `<${tag(node)} ${Array<Attr>()
.map.call(node.attributes, attr => `${attr.nodeName}="${escape(attr.value)}"`)
.map.call(node.attributes, attr => `${attr.nodeName}="${escapeHTML(attr.value).replace(/"/g, '&quot;')}"`)
.join(' ')}>`;
}
@ -111,7 +110,7 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
while (original.length || highlighted.length) {
let stream = selectStream();
result += escape(value.substring(processed, stream[0].offset));
result += escapeHTML(value.substring(processed, stream[0].offset));
processed = stream[0].offset;
if (stream === original) {
/*
@ -135,5 +134,522 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
render(stream.splice(0, 1)[0]);
}
}
return result + escape(value.substr(processed));
return result + escapeHTML(value.substr(processed));
}
// https://github.com/hexojs/hexo-util/blob/979873b63a725377c2bd6ad834d790023496130d/lib/highlight.js#L123
export function closeTags(res: HighlightResult): HighlightResult {
const tokenStack = new Array<string>();
res.value = res.value
.split('\n')
.map(line => {
const prepend = tokenStack.map(token => `<span class="${token}">`).join('');
const matches = line.matchAll(/(<span class="(.*?)">|<\/span>)/g);
Array.from(matches).forEach(match => {
if (match[0] === '</span>') tokenStack.shift();
else tokenStack.unshift(match[2]);
});
const append = '</span>'.repeat(tokenStack.length);
return prepend + line + append;
})
.join('\n');
return res;
}
// Sourced from https://github.com/highlightjs/highlight.js/blob/main/SUPPORTED_LANGUAGES.md and
// https://github.com/exercism/v2-website/blob/main/config/initializers/prism.rb#L187-L315
const languagesToExt: { [_: string]: string } = {
'1c': '1c',
abnf: 'abnf',
accesslog: 'accesslog',
as: 'actionscript',
adb: 'ada',
ada: 'ada',
ads: 'ada',
angelscript: 'angelscript',
// asc: 'angelscript',
apache: 'apache',
applescript: 'applescript',
scpt: 'applescript',
arcade: 'arcade',
cpp: 'cpp',
hpp: 'cpp',
arduino: 'arduino',
ino: 'arduino',
armasm: 'armasm',
arm: 'armasm',
xml: 'xml',
html: 'xml',
xhtml: 'xml',
rss: 'xml',
atom: 'xml',
xjb: 'xml',
xsd: 'xml',
xsl: 'xml',
plist: 'xml',
svg: 'xml',
asciidoc: 'asciidoc',
adoc: 'asciidoc',
asc: 'asciidoc',
aspectj: 'aspectj',
ahk: 'autohotkey',
ahkl: 'autohotkey',
au3: 'autoit',
avrasm: 'avrasm',
awk: 'awk',
axapta: 'axapta',
'x++': 'axapta',
bash: 'bash',
sh: 'bash',
zsh: 'bash',
b: 'basic',
bnf: 'bnf',
bf: 'brainfuck',
c: 'c',
h: 'c',
cats: 'c',
idc: 'c',
cal: 'cal',
capnproto: 'capnproto',
capnp: 'capnproto',
ceylon: 'ceylon',
clean: 'clean',
clj: 'clojure',
boot: 'clojure',
cl2: 'clojure',
cljc: 'clojure',
cljs: 'clojure',
'cljs.hl': 'clojure',
cljscm: 'clojure',
cljx: 'clojure',
hic: 'clojure',
'clojure-repl': 'clojure-repl',
cmake: 'cmake',
'cmake.in': 'cmake',
coffee: 'coffeescript',
_coffee: 'coffeescript',
cake: 'coffeescript',
cjsx: 'coffeescript',
iced: 'coffeescript',
cson: 'coffeescript',
coq: 'coq',
cos: 'cos',
cls: 'cos',
crmsh: 'crmsh',
crm: 'crmsh',
pcmk: 'crmsh',
cr: 'crystal',
cs: 'csharp',
csx: 'csharp',
csp: 'csp',
css: 'css',
d: 'd',
di: 'd',
md: 'markdown',
markdown: 'markdown',
mdown: 'markdown',
mdwn: 'markdown',
mkd: 'markdown',
mkdn: 'markdown',
mkdown: 'markdown',
ronn: 'markdown',
workbook: 'markdown',
dart: 'dart',
dpr: 'delphi',
dfm: 'delphi',
pas: 'delphi',
pascal: 'delphi',
diff: 'diff',
patch: 'diff',
django: 'django',
jinja: 'django',
dns: 'dns',
zone: 'dns',
bind: 'dns',
dockerfile: 'dockerfile',
docker: 'dockerfile',
dos: 'dos',
bat: 'dos',
cmd: 'dos',
dsconfig: 'dsconfig',
dts: 'dts',
dust: 'dust',
dst: 'dust',
ebnf: 'ebnf',
ex: 'elixir',
exs: 'elixir',
elm: 'elm',
rb: 'ruby',
builder: 'ruby',
eye: 'ruby',
gemspec: 'ruby',
god: 'ruby',
jbuilder: 'ruby',
mspec: 'ruby',
pluginspec: 'ruby',
podspec: 'ruby',
rabl: 'ruby',
rake: 'ruby',
rbuild: 'ruby',
rbw: 'ruby',
rbx: 'ruby',
ru: 'ruby',
ruby: 'ruby',
spec: 'ruby',
thor: 'ruby',
watchr: 'ruby',
erb: 'erb',
'erlang-repl': 'erlang-repl',
erl: 'erlang',
'app.src': 'erlang',
escript: 'erlang',
hrl: 'erlang',
xrl: 'erlang',
yrl: 'erlang',
excel: 'excel',
xls: 'excel',
xlsx: 'excel',
fix: 'fix',
flix: 'flix',
f90: 'fortran',
f: 'fortran',
f03: 'fortran',
f08: 'fortran',
f77: 'fortran',
f95: 'fortran',
for: 'fortran',
fpp: 'fortran',
fs: 'fsharp',
fsx: 'fsharp',
gams: 'gams',
gms: 'gams',
gauss: 'gauss',
gss: 'gauss',
gcode: 'gcode',
nc: 'gcode',
gherkin: 'gherkin',
glsl: 'glsl',
fp: 'glsl',
frag: 'glsl',
frg: 'glsl',
fsh: 'glsl',
fshader: 'glsl',
geo: 'glsl',
geom: 'glsl',
glslv: 'glsl',
gshader: 'glsl',
shader: 'glsl',
tesc: 'glsl',
tese: 'glsl',
vert: 'glsl',
vrx: 'glsl',
vsh: 'glsl',
vshader: 'glsl',
gml: 'gml',
go: 'go',
bal: 'go',
golo: 'golo',
gololang: 'golo',
gradle: 'gradle',
groovy: 'groovy',
grt: 'groovy',
gtpl: 'groovy',
gvy: 'groovy',
haml: 'haml',
'haml.deface': 'haml',
handlebars: 'handlebars',
hbs: 'handlebars',
'html.hbs': 'handlebars',
'html.handlebars': 'handlebars',
hs: 'haskell',
hsc: 'haskell',
idr: 'haskell',
purs: 'haskell',
hx: 'haxe',
hxsl: 'haxe',
hsp: 'hsp',
htmlbars: 'htmlbars',
http: 'http',
https: 'http',
hy: 'hy',
inform7: 'inform7',
i7: 'inform7',
ini: 'ini',
toml: 'ini',
cfg: 'ini',
prefs: 'ini',
// properties: 'ini',
irpf90: 'irpf90',
isbl: 'isbl',
java: 'java',
jsp: 'java',
js: 'javascript',
jsx: 'javascript',
_js: 'javascript',
bones: 'javascript',
es: 'javascript',
es6: 'javascript',
gs: 'javascript',
jake: 'javascript',
jsb: 'javascript',
jscad: 'javascript',
jsfl: 'javascript',
jsm: 'javascript',
jss: 'javascript',
mjs: 'javascript',
njs: 'javascript',
pac: 'javascript',
sjs: 'javascript',
ssjs: 'javascript',
xsjs: 'javascript',
xsjslib: 'javascript',
cfc: 'javascript',
'jboss-cli': 'jboss-cli',
json: 'json',
avsc: 'json',
geojson: 'json',
gltf: 'json',
'JSON-tmLanguage': 'json',
jsonl: 'json',
tfstate: 'json',
'tfstate.backup': 'json',
topojson: 'json',
webapp: 'json',
webmanifest: 'json',
jl: 'julia',
'julia-repl': 'julia-repl',
kt: 'kotlin',
ktm: 'kotlin',
kts: 'kotlin',
lasso: 'lasso',
// ls: 'lasso',
lassoscript: 'lasso',
tex: 'latex',
ldif: 'ldif',
leaf: 'leaf',
less: 'less',
lisp: 'lisp',
factor: 'lisp',
livecodeserver: 'livecodeserver',
ls: 'livescript',
_ls: 'livescript',
llvm: 'llvm',
lsl: 'lsl',
lua: 'lua',
nse: 'lua',
p8: 'lua',
pd_lua: 'lua',
rbxs: 'lua',
wlua: 'lua',
mak: 'makefile',
make: 'makefile',
mk: 'makefile',
mkfile: 'makefile',
mathematica: 'mathematica',
mma: 'mathematica',
wl: 'mathematica',
matlab: 'matlab',
maxima: 'maxima',
mel: 'mel',
mercury: 'mercury',
mipsasm: 'mipsasm',
miz: 'mizar',
voc: 'mizar',
al: 'perl',
cgi: 'perl',
fcgi: 'perl',
perl: 'perl',
ph: 'perl',
plx: 'perl',
pl: 'perl',
pm: 'perl',
psgi: 'perl',
t: 'perl',
mojolicious: 'mojolicious',
monkey: 'monkey',
monkey2: 'monkey',
moonscript: 'moonscript',
moon: 'moonscript',
n1ql: 'n1ql',
nginxconf: 'nginx',
nim: 'nim',
nimrod: 'nim',
nix: 'nix',
nsi: 'nsis',
nsh: 'nsis',
m: 'objectivec',
objc: 'objectivec',
mm: 'objectivec',
'obj-c': 'objectivec',
'obj-c++': 'objectivec',
'objective-c++': 'objectivec',
fun: 'ocaml',
sig: 'ocaml',
// sml: 'ocaml',
ml: 'ocaml',
mli: 'ocaml',
eliom: 'ocaml',
eliomi: 'ocaml',
ml4: 'ocaml',
mll: 'ocaml',
mly: 'ocaml',
openscad: 'openscad',
oxygene: 'oxygene',
parser3: 'parser3',
pf: 'pf',
'pf.conf': 'pf',
pgsql: 'pgsql',
postgres: 'pgsql',
postgresql: 'pgsql',
php: 'php',
aw: 'php',
ctp: 'php',
inc: 'php',
php3: 'php',
php4: 'php',
php5: 'php',
phps: 'php',
phpt: 'php',
'php-template': 'php-template',
plaintext: 'plaintext',
txt: 'plaintext',
text: 'plaintext',
pony: 'pony',
ps: 'powershell',
ps1: 'powershell',
psd1: 'powershell',
psm1: 'powershell',
pde: 'processing',
profile: 'profile',
pro: 'prolog',
prolog: 'prolog',
yap: 'prolog',
properties: 'properties',
proto: 'protobuf',
puppet: 'puppet',
pp: 'puppet',
purebasic: 'purebasic',
py: 'python',
bzl: 'python',
gyp: 'python',
gypi: 'python',
lmi: 'python',
py3: 'python',
pyde: 'python',
pyi: 'python',
pyp: 'python',
pyt: 'python',
pyw: 'python',
rpy: 'python',
tac: 'python',
wsgi: 'python',
xpy: 'python',
'python-repl': 'python-repl',
pycon: 'python-repl',
q: 'q',
k: 'q',
kdb: 'q',
qml: 'qml',
r: 'r',
rd: 'r',
rsx: 'r',
reasonml: 'reasonml',
re: 'reasonml',
rib: 'rib',
roboconf: 'roboconf',
graph: 'roboconf',
instances: 'roboconf',
routeros: 'routeros',
rsl: 'rsl',
ruleslanguage: 'ruleslanguage',
rs: 'rust',
'rs.in': 'rust',
sas: 'sas',
// pony: 'scala',
scala: 'scala',
kojo: 'scala',
sbt: 'scala',
sc: 'scala',
scm: 'scheme',
sch: 'scheme',
sld: 'scheme',
sls: 'scheme',
sps: 'scheme',
ss: 'scheme',
rkt: 'scheme',
scilab: 'scilab',
scss: 'scss',
shell: 'shell',
smali: 'smali',
st: 'smalltalk',
sml: 'sml',
sqf: 'sqf',
sql: 'sql',
cql: 'sql',
ddl: 'sql',
mysql: 'sql',
prc: 'sql',
tab: 'sql',
udf: 'sql',
viw: 'sql',
stan: 'stan',
stanfuncs: 'stan',
stata: 'stata',
step21: 'step21',
step: 'step21',
stp: 'step21',
styl: 'stylus',
subunit: 'subunit',
swift: 'swift',
taggerscript: 'taggerscript',
yml: 'yaml',
mir: 'yaml',
reek: 'yaml',
rviz: 'yaml',
'sublime-syntax': 'yaml',
syntax: 'yaml',
yaml: 'yaml',
'yaml-tmlanguage': 'yaml',
'yml.mysql': 'yaml',
tap: 'tap',
tcl: 'tcl',
adp: 'tcl',
tm: 'tcl',
thrift: 'thrift',
tp: 'tp',
twig: 'twig',
craftcms: 'twig',
ts: 'typescript',
tsx: 'typescript',
vala: 'vala',
vbnet: 'vbnet',
vb: 'vbnet',
vbscript: 'vbscript',
vbs: 'vbscript',
'vbscript-html': 'vbscript-html',
v: 'verilog',
veo: 'verilog',
vhdl: 'vhdl',
vhd: 'vhdl',
vhf: 'vhdl',
vhi: 'vhdl',
vho: 'vhdl',
vhs: 'vhdl',
vht: 'vhdl',
vhw: 'vhdl',
vim: 'vim',
x86asm: 'x86asm',
xl: 'xl',
xquery: 'xquery',
xpath: 'xquery',
xq: 'xquery',
zephir: 'zephir',
zep: 'zephir',
};
export function getLanguage(fileExtension: string): string {
return languagesToExt[fileExtension] ?? 'plaintext';
}

View file

@ -1,11 +1,11 @@
// Require the highlight.js library without languages
import highlightJS from 'highlight.js/lib/highlight.js';
import highlightJS from 'highlight.js/lib/core';
// Convert to imports
// ^highlightJS\.registerLanguage\('(.+)', require\('highlight.js\/lib\/languages\/(.+)'\)\);$
// ^hljs\.registerLanguage\('(.+)', require\('\./languages\/(.+)'\)\);$
// import $1 from 'highlight.js/lib/languages/$2';
// import 1c from 'highlight.js/lib/languages/1c';
// import _1c from 'highlight.js/lib/languages/1c';
// import abnf from 'highlight.js/lib/languages/abnf';
// import accesslog from 'highlight.js/lib/languages/accesslog';
// import actionscript from 'highlight.js/lib/languages/actionscript';
@ -29,27 +29,28 @@ import bash from 'highlight.js/lib/languages/bash';
// import basic from 'highlight.js/lib/languages/basic';
// import bnf from 'highlight.js/lib/languages/bnf';
// import brainfuck from 'highlight.js/lib/languages/brainfuck';
import c from 'highlight.js/lib/languages/c';
// import cal from 'highlight.js/lib/languages/cal';
// import capnproto from 'highlight.js/lib/languages/capnproto';
// import ceylon from 'highlight.js/lib/languages/ceylon';
// import clean from 'highlight.js/lib/languages/clean';
import clojure from 'highlight.js/lib/languages/clojure';
import clojureRepl from 'highlight.js/lib/languages/clojure-repl';
import cmake from 'highlight.js/lib/languages/cmake';
import coffeescript from 'highlight.js/lib/languages/coffeescript';
// import clojureRepl from 'highlight.js/lib/languages/clojure-repl';
// import cmake from 'highlight.js/lib/languages/cmake';
// import coffeescript from 'highlight.js/lib/languages/coffeescript';
// import coq from 'highlight.js/lib/languages/coq';
// import cos from 'highlight.js/lib/languages/cos';
// import crmsh from 'highlight.js/lib/languages/crmsh';
import crystal from 'highlight.js/lib/languages/crystal';
import cs from 'highlight.js/lib/languages/cs';
import csharp from 'highlight.js/lib/languages/csharp';
import csp from 'highlight.js/lib/languages/csp';
import css from 'highlight.js/lib/languages/css';
import d from 'highlight.js/lib/languages/d';
// import d from 'highlight.js/lib/languages/d';
import markdown from 'highlight.js/lib/languages/markdown';
import dart from 'highlight.js/lib/languages/dart';
// import delphi from 'highlight.js/lib/languages/delphi';
import diff from 'highlight.js/lib/languages/diff';
import django from 'highlight.js/lib/languages/django';
// import django from 'highlight.js/lib/languages/django';
// import dns from 'highlight.js/lib/languages/dns';
import dockerfile from 'highlight.js/lib/languages/dockerfile';
// import dos from 'highlight.js/lib/languages/dos';
@ -60,10 +61,10 @@ import dockerfile from 'highlight.js/lib/languages/dockerfile';
import elixir from 'highlight.js/lib/languages/elixir';
import elm from 'highlight.js/lib/languages/elm';
import ruby from 'highlight.js/lib/languages/ruby';
import erb from 'highlight.js/lib/languages/erb';
import erlangRepl from 'highlight.js/lib/languages/erlang-repl';
// import erb from 'highlight.js/lib/languages/erb';
// import erlangRepl from 'highlight.js/lib/languages/erlang-repl';
import erlang from 'highlight.js/lib/languages/erlang';
import excel from 'highlight.js/lib/languages/excel';
// import excel from 'highlight.js/lib/languages/excel';
// import fix from 'highlight.js/lib/languages/fix';
// import flix from 'highlight.js/lib/languages/flix';
// import fortran from 'highlight.js/lib/languages/fortran';
@ -83,8 +84,8 @@ import handlebars from 'highlight.js/lib/languages/handlebars';
import haskell from 'highlight.js/lib/languages/haskell';
// import haxe from 'highlight.js/lib/languages/haxe';
// import hsp from 'highlight.js/lib/languages/hsp';
import htmlbars from 'highlight.js/lib/languages/htmlbars';
import http from 'highlight.js/lib/languages/http';
// import htmlbars from 'highlight.js/lib/languages/htmlbars';
// import http from 'highlight.js/lib/languages/http';
// import hy from 'highlight.js/lib/languages/hy';
// import inform7 from 'highlight.js/lib/languages/inform7';
import ini from 'highlight.js/lib/languages/ini';
@ -92,24 +93,25 @@ import ini from 'highlight.js/lib/languages/ini';
// import isbl from 'highlight.js/lib/languages/isbl';
import java from 'highlight.js/lib/languages/java';
import javascript from 'highlight.js/lib/languages/javascript';
// import jboss-cli from 'highlight.js/lib/languages/jboss-cli';
// import jbossCli from 'highlight.js/lib/languages/jboss-cli';
import json from 'highlight.js/lib/languages/json';
import julia from 'highlight.js/lib/languages/julia';
import juliaRepl from 'highlight.js/lib/languages/julia-repl';
// import julia from 'highlight.js/lib/languages/julia';
// import juliaRepl from 'highlight.js/lib/languages/julia-repl';
import kotlin from 'highlight.js/lib/languages/kotlin';
// import lasso from 'highlight.js/lib/languages/lasso';
// import latex from 'highlight.js/lib/languages/latex';
// import ldif from 'highlight.js/lib/languages/ldif';
// import leaf from 'highlight.js/lib/languages/leaf';
import less from 'highlight.js/lib/languages/less';
import lisp from 'highlight.js/lib/languages/lisp';
// import livecodeserver from 'highlight.js/lib/languages/livecodeserver';
// import livescript from 'highlight.js/lib/languages/livescript';
import llvm from 'highlight.js/lib/languages/llvm';
// import llvm from 'highlight.js/lib/languages/llvm';
// import lsl from 'highlight.js/lib/languages/lsl';
import lua from 'highlight.js/lib/languages/lua';
import makefile from 'highlight.js/lib/languages/makefile';
import mathematica from 'highlight.js/lib/languages/mathematica';
import matlab from 'highlight.js/lib/languages/matlab';
// import mathematica from 'highlight.js/lib/languages/mathematica';
// import matlab from 'highlight.js/lib/languages/matlab';
// import maxima from 'highlight.js/lib/languages/maxima';
// import mel from 'highlight.js/lib/languages/mel';
// import mercury from 'highlight.js/lib/languages/mercury';
@ -121,17 +123,18 @@ import perl from 'highlight.js/lib/languages/perl';
// import moonscript from 'highlight.js/lib/languages/moonscript';
// import n1ql from 'highlight.js/lib/languages/n1ql';
import nginx from 'highlight.js/lib/languages/nginx';
// import nimrod from 'highlight.js/lib/languages/nimrod';
import nix from 'highlight.js/lib/languages/nix';
// import nim from 'highlight.js/lib/languages/nim';
// import nix from 'highlight.js/lib/languages/nix';
// import nsis from 'highlight.js/lib/languages/nsis';
import objectivec from 'highlight.js/lib/languages/objectivec';
import ocaml from 'highlight.js/lib/languages/ocaml';
// import ocaml from 'highlight.js/lib/languages/ocaml';
// import openscad from 'highlight.js/lib/languages/openscad';
// import oxygene from 'highlight.js/lib/languages/oxygene';
// import parser3 from 'highlight.js/lib/languages/parser3';
// import pf from 'highlight.js/lib/languages/pf';
import pgsql from 'highlight.js/lib/languages/pgsql';
import php from 'highlight.js/lib/languages/php';
// import phpTemplate from 'highlight.js/lib/languages/php-template';
import plaintext from 'highlight.js/lib/languages/plaintext';
// import pony from 'highlight.js/lib/languages/pony';
import powershell from 'highlight.js/lib/languages/powershell';
@ -140,13 +143,14 @@ import powershell from 'highlight.js/lib/languages/powershell';
// import prolog from 'highlight.js/lib/languages/prolog';
import properties from 'highlight.js/lib/languages/properties';
import protobuf from 'highlight.js/lib/languages/protobuf';
import puppet from 'highlight.js/lib/languages/puppet';
// import puppet from 'highlight.js/lib/languages/puppet';
// import purebasic from 'highlight.js/lib/languages/purebasic';
import python from 'highlight.js/lib/languages/python';
// import pythonRepl from 'highlight.js/lib/languages/python-repl';
// import q from 'highlight.js/lib/languages/q';
// import qml from 'highlight.js/lib/languages/qml';
import r from 'highlight.js/lib/languages/r';
import reasonml from 'highlight.js/lib/languages/reasonml';
// import r from 'highlight.js/lib/languages/r';
// import reasonml from 'highlight.js/lib/languages/reasonml';
// import rib from 'highlight.js/lib/languages/rib';
// import roboconf from 'highlight.js/lib/languages/roboconf';
// import routeros from 'highlight.js/lib/languages/routeros';
@ -155,7 +159,7 @@ import reasonml from 'highlight.js/lib/languages/reasonml';
import rust from 'highlight.js/lib/languages/rust';
// import sas from 'highlight.js/lib/languages/sas';
import scala from 'highlight.js/lib/languages/scala';
import scheme from 'highlight.js/lib/languages/scheme';
// import scheme from 'highlight.js/lib/languages/scheme';
// import scilab from 'highlight.js/lib/languages/scilab';
import scss from 'highlight.js/lib/languages/scss';
import shell from 'highlight.js/lib/languages/shell';
@ -167,14 +171,13 @@ import sql from 'highlight.js/lib/languages/sql';
// import stan from 'highlight.js/lib/languages/stan';
// import stata from 'highlight.js/lib/languages/stata';
// import step21 from 'highlight.js/lib/languages/step21';
import stylus from 'highlight.js/lib/languages/stylus';
// import stylus from 'highlight.js/lib/languages/stylus';
// import subunit from 'highlight.js/lib/languages/subunit';
import swift from 'highlight.js/lib/languages/swift';
// import taggerscript from 'highlight.js/lib/languages/taggerscript';
import yaml from 'highlight.js/lib/languages/yaml';
// import tap from 'highlight.js/lib/languages/tap';
// import tcl from 'highlight.js/lib/languages/tcl';
import tex from 'highlight.js/lib/languages/tex';
// import thrift from 'highlight.js/lib/languages/thrift';
// import tp from 'highlight.js/lib/languages/tp';
// import twig from 'highlight.js/lib/languages/twig';
@ -182,21 +185,21 @@ import typescript from 'highlight.js/lib/languages/typescript';
// import vala from 'highlight.js/lib/languages/vala';
// import vbnet from 'highlight.js/lib/languages/vbnet';
// import vbscript from 'highlight.js/lib/languages/vbscript';
// import vbscript-html from 'highlight.js/lib/languages/vbscript-html';
// import vbscriptHtml from 'highlight.js/lib/languages/vbscript-html';
// import verilog from 'highlight.js/lib/languages/verilog';
// import vhdl from 'highlight.js/lib/languages/vhdl';
import vim from 'highlight.js/lib/languages/vim';
// import vim from 'highlight.js/lib/languages/vim';
// import x86asm from 'highlight.js/lib/languages/x86asm';
// import xl from 'highlight.js/lib/languages/xl';
// import xquery from 'highlight.js/lib/languages/xquery';
// import zephir from 'highlight.js/lib/languages/zephir';
// Convert to registerLanguage
// ^highlightJS\.registerLanguage\('(.+)', require\('highlight.js\/lib\/languages\/(.+)'\)\);$
// ^hljs\.registerLanguage\('(.+)', require\('\./languages\/(.+)'\)\);$
// highlightJS.registerLanguage('$1', $1);
// Separately require languages
// highlightJS.registerLanguage('1c', 1c);
// highlightJS.registerLanguage('1c', _1c);
// highlightJS.registerLanguage('abnf', abnf);
// highlightJS.registerLanguage('accesslog', accesslog);
// highlightJS.registerLanguage('actionscript', actionscript);
@ -220,27 +223,28 @@ highlightJS.registerLanguage('bash', bash);
// highlightJS.registerLanguage('basic', basic);
// highlightJS.registerLanguage('bnf', bnf);
// highlightJS.registerLanguage('brainfuck', brainfuck);
highlightJS.registerLanguage('c', c);
// highlightJS.registerLanguage('cal', cal);
// highlightJS.registerLanguage('capnproto', capnproto);
// highlightJS.registerLanguage('ceylon', ceylon);
// highlightJS.registerLanguage('clean', clean);
highlightJS.registerLanguage('clojure', clojure);
highlightJS.registerLanguage('clojure-repl', clojureRepl);
highlightJS.registerLanguage('cmake', cmake);
highlightJS.registerLanguage('coffeescript', coffeescript);
// highlightJS.registerLanguage('clojure-repl', clojureRepl);
// highlightJS.registerLanguage('cmake', cmake);
// highlightJS.registerLanguage('coffeescript', coffeescript);
// highlightJS.registerLanguage('coq', coq);
// highlightJS.registerLanguage('cos', cos);
// highlightJS.registerLanguage('crmsh', crmsh);
highlightJS.registerLanguage('crystal', crystal);
highlightJS.registerLanguage('cs', cs);
highlightJS.registerLanguage('csharp', csharp);
highlightJS.registerLanguage('csp', csp);
highlightJS.registerLanguage('css', css);
highlightJS.registerLanguage('d', d);
// highlightJS.registerLanguage('d', d);
highlightJS.registerLanguage('markdown', markdown);
highlightJS.registerLanguage('dart', dart);
// highlightJS.registerLanguage('delphi', delphi);
highlightJS.registerLanguage('diff', diff);
highlightJS.registerLanguage('django', django);
// highlightJS.registerLanguage('django', django);
// highlightJS.registerLanguage('dns', dns);
highlightJS.registerLanguage('dockerfile', dockerfile);
// highlightJS.registerLanguage('dos', dos);
@ -251,10 +255,10 @@ highlightJS.registerLanguage('dockerfile', dockerfile);
highlightJS.registerLanguage('elixir', elixir);
highlightJS.registerLanguage('elm', elm);
highlightJS.registerLanguage('ruby', ruby);
highlightJS.registerLanguage('erb', erb);
highlightJS.registerLanguage('erlang-repl', erlangRepl);
// highlightJS.registerLanguage('erb', erb);
// highlightJS.registerLanguage('erlang-repl', erlangRepl);
highlightJS.registerLanguage('erlang', erlang);
highlightJS.registerLanguage('excel', excel);
// highlightJS.registerLanguage('excel', excel);
// highlightJS.registerLanguage('fix', fix);
// highlightJS.registerLanguage('flix', flix);
// highlightJS.registerLanguage('fortran', fortran);
@ -274,8 +278,8 @@ highlightJS.registerLanguage('handlebars', handlebars);
highlightJS.registerLanguage('haskell', haskell);
// highlightJS.registerLanguage('haxe', haxe);
// highlightJS.registerLanguage('hsp', hsp);
highlightJS.registerLanguage('htmlbars', htmlbars);
highlightJS.registerLanguage('http', http);
// highlightJS.registerLanguage('htmlbars', htmlbars);
// highlightJS.registerLanguage('http', http);
// highlightJS.registerLanguage('hy', hy);
// highlightJS.registerLanguage('inform7', inform7);
highlightJS.registerLanguage('ini', ini);
@ -283,24 +287,25 @@ highlightJS.registerLanguage('ini', ini);
// highlightJS.registerLanguage('isbl', isbl);
highlightJS.registerLanguage('java', java);
highlightJS.registerLanguage('javascript', javascript);
// highlightJS.registerLanguage('jboss-cli', jboss-cli);
// highlightJS.registerLanguage('jboss-cli', jbossCli);
highlightJS.registerLanguage('json', json);
highlightJS.registerLanguage('julia', julia);
highlightJS.registerLanguage('julia-repl', juliaRepl);
// highlightJS.registerLanguage('julia', julia);
// highlightJS.registerLanguage('julia-repl', juliaRepl);
highlightJS.registerLanguage('kotlin', kotlin);
// highlightJS.registerLanguage('lasso', lasso);
// highlightJS.registerLanguage('latex', latex);
// highlightJS.registerLanguage('ldif', ldif);
// highlightJS.registerLanguage('leaf', leaf);
highlightJS.registerLanguage('less', less);
highlightJS.registerLanguage('lisp', lisp);
// highlightJS.registerLanguage('livecodeserver', livecodeserver);
// highlightJS.registerLanguage('livescript', livescript);
highlightJS.registerLanguage('llvm', llvm);
// highlightJS.registerLanguage('llvm', llvm);
// highlightJS.registerLanguage('lsl', lsl);
highlightJS.registerLanguage('lua', lua);
highlightJS.registerLanguage('makefile', makefile);
highlightJS.registerLanguage('mathematica', mathematica);
highlightJS.registerLanguage('matlab', matlab);
// highlightJS.registerLanguage('mathematica', mathematica);
// highlightJS.registerLanguage('matlab', matlab);
// highlightJS.registerLanguage('maxima', maxima);
// highlightJS.registerLanguage('mel', mel);
// highlightJS.registerLanguage('mercury', mercury);
@ -312,17 +317,18 @@ highlightJS.registerLanguage('perl', perl);
// highlightJS.registerLanguage('moonscript', moonscript);
// highlightJS.registerLanguage('n1ql', n1ql);
highlightJS.registerLanguage('nginx', nginx);
// highlightJS.registerLanguage('nimrod', nimrod);
highlightJS.registerLanguage('nix', nix);
// highlightJS.registerLanguage('nim', nim);
// highlightJS.registerLanguage('nix', nix);
// highlightJS.registerLanguage('nsis', nsis);
highlightJS.registerLanguage('objectivec', objectivec);
highlightJS.registerLanguage('ocaml', ocaml);
// highlightJS.registerLanguage('ocaml', ocaml);
// highlightJS.registerLanguage('openscad', openscad);
// highlightJS.registerLanguage('oxygene', oxygene);
// highlightJS.registerLanguage('parser3', parser3);
// highlightJS.registerLanguage('pf', pf);
highlightJS.registerLanguage('pgsql', pgsql);
highlightJS.registerLanguage('php', php);
// highlightJS.registerLanguage('php-template', phpTemplate);
highlightJS.registerLanguage('plaintext', plaintext);
// highlightJS.registerLanguage('pony', pony);
highlightJS.registerLanguage('powershell', powershell);
@ -331,13 +337,14 @@ highlightJS.registerLanguage('powershell', powershell);
// highlightJS.registerLanguage('prolog', prolog);
highlightJS.registerLanguage('properties', properties);
highlightJS.registerLanguage('protobuf', protobuf);
highlightJS.registerLanguage('puppet', puppet);
// highlightJS.registerLanguage('puppet', puppet);
// highlightJS.registerLanguage('purebasic', purebasic);
highlightJS.registerLanguage('python', python);
// highlightJS.registerLanguage('python-repl', pythonRepl);
// highlightJS.registerLanguage('q', q);
// highlightJS.registerLanguage('qml', qml);
highlightJS.registerLanguage('r', r);
highlightJS.registerLanguage('reasonml', reasonml);
// highlightJS.registerLanguage('r', r);
// highlightJS.registerLanguage('reasonml', reasonml);
// highlightJS.registerLanguage('rib', rib);
// highlightJS.registerLanguage('roboconf', roboconf);
// highlightJS.registerLanguage('routeros', routeros);
@ -346,7 +353,7 @@ highlightJS.registerLanguage('reasonml', reasonml);
highlightJS.registerLanguage('rust', rust);
// highlightJS.registerLanguage('sas', sas);
highlightJS.registerLanguage('scala', scala);
highlightJS.registerLanguage('scheme', scheme);
// highlightJS.registerLanguage('scheme', scheme);
// highlightJS.registerLanguage('scilab', scilab);
highlightJS.registerLanguage('scss', scss);
highlightJS.registerLanguage('shell', shell);
@ -358,14 +365,13 @@ highlightJS.registerLanguage('sql', sql);
// highlightJS.registerLanguage('stan', stan);
// highlightJS.registerLanguage('stata', stata);
// highlightJS.registerLanguage('step21', step21);
highlightJS.registerLanguage('stylus', stylus);
// highlightJS.registerLanguage('stylus', stylus);
// highlightJS.registerLanguage('subunit', subunit);
highlightJS.registerLanguage('swift', swift);
// highlightJS.registerLanguage('taggerscript', taggerscript);
highlightJS.registerLanguage('yaml', yaml);
// highlightJS.registerLanguage('tap', tap);
// highlightJS.registerLanguage('tcl', tcl);
highlightJS.registerLanguage('tex', tex);
// highlightJS.registerLanguage('thrift', thrift);
// highlightJS.registerLanguage('tp', tp);
// highlightJS.registerLanguage('twig', twig);
@ -373,10 +379,10 @@ highlightJS.registerLanguage('typescript', typescript);
// highlightJS.registerLanguage('vala', vala);
// highlightJS.registerLanguage('vbnet', vbnet);
// highlightJS.registerLanguage('vbscript', vbscript);
// highlightJS.registerLanguage('vbscript-html', vbscript-html);
// highlightJS.registerLanguage('vbscript-html', vbscriptHtml);
// highlightJS.registerLanguage('verilog', verilog);
// highlightJS.registerLanguage('vhdl', vhdl);
highlightJS.registerLanguage('vim', vim);
// highlightJS.registerLanguage('vim', vim);
// highlightJS.registerLanguage('x86asm', x86asm);
// highlightJS.registerLanguage('xl', xl);
// highlightJS.registerLanguage('xquery', xquery);

5
tsconfig.eslint.json Normal file
View file

@ -0,0 +1,5 @@
{
"extends": "./tsconfig.json",
"exclude": ["node_modules"],
"include": ["./**/*"]
}

View file

@ -1,28 +1,37 @@
{
"include": ["src/**/*", "typings/**/*"],
"exclude": ["node_modules", "src/__tests__/**"],
"compilerOptions": {
"outDir": "./_target",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"lib": ["es2015", "dom"],
"outDir": "bundles-out",
"module": "CommonJS",
"moduleResolution": "Node",
"target": "ES6",
"lib": ["ES6", "DOM"],
"jsx": "preserve",
"allowJs": false,
"checkJs": false,
"importHelpers": false,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noEmit": false,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"incremental": false,
"strictNullChecks": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"alwaysStrict": true,
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true,
"noUnusedParameters": true,
"noUnusedLocals": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true
},
"include": ["./src/**/*", "./typings/**/*"],
"exclude": ["node_modules", "./src/__tests__/*"]
"noImplicitThis": true
}
}

View file

@ -1,5 +0,0 @@
declare module 'highlight.js/lib/highlight.js' {
import hljs from 'highlight.js';
export = hljs;
}

View file

@ -1,5 +0,0 @@
declare module 'highlight.js/lib/languages/*' {
import { HLJSStatic, IModeBase } from 'highlight.js';
export default function(hljs?: HLJSStatic): IModeBase;
}

View file

@ -3,17 +3,52 @@ import path from 'path';
import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import CopyWebpackPlugin from 'copy-webpack-plugin';
import CopyPlugin from 'copy-webpack-plugin';
const pages = ['index', 'demo'];
type Plugin = ((this: webpack.Compiler, compiler: webpack.Compiler) => void) | webpack.WebpackPluginInstance;
function plugins(page: string): Plugin[] {
return [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
new HtmlWebpackPlugin({
hash: true,
inject: true,
title: `${page} page`,
filename: `${page}.html`,
template: `./website/templates/pages/${page}/${page}.handlebars`,
minify: {
html5: true,
collapseWhitespace: true,
caseSensitive: true,
removeEmptyElements: false,
removeComments: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
new CopyPlugin({
patterns: [
{ from: 'website/favicon.ico', to: 'favicon.ico' },
{ from: 'website/robots.txt', to: 'robots.txt' },
{ from: 'website/sitemap.xml', to: 'sitemap.xml' },
],
}),
];
}
const config: webpack.Configuration[] = pages.map(page => {
return {
devServer: {
port: 3000,
open: true,
contentBase: path.join(__dirname, './website'),
},
entry: {
[page]: `./website/templates/pages/${page}/${page}.ts`,
},
@ -108,39 +143,7 @@ const config: webpack.Configuration[] = pages.map(page => {
},
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].css',
chunkFilename: '[id].css',
}),
new HtmlWebpackPlugin({
hash: true,
inject: true,
title: `${page} page`,
filename: `${page}.html`,
template: `./website/templates/pages/${page}/${page}.handlebars`,
minify: {
html5: true,
collapseWhitespace: true,
caseSensitive: true,
removeEmptyElements: false,
removeComments: true,
removeRedundantAttributes: true,
useShortDoctype: true,
removeEmptyAttributes: true,
removeStyleLinkTypeAttributes: true,
keepClosingSlash: true,
minifyJS: true,
minifyCSS: true,
minifyURLs: true,
},
}),
new CopyWebpackPlugin([
{ from: 'website/favicon.ico', to: 'favicon.ico' },
{ from: 'website/robots.txt', to: 'robots.txt' },
{ from: 'website/sitemap.xml', to: 'sitemap.xml' },
]),
],
plugins: plugins(page),
};
});

View file

@ -2,7 +2,7 @@
<div class="hero-body">
<div class="container">
<h1 class="title is-size-1 is-spaced">Demo<a href="#help">
<svg height="32" class="octicon octicon-unverified" viewBox="0 0 16 16" version="1.1" width="64"
<svg fill="currentColor" height="32" class="octicon octicon-unverified" viewBox="0 0 16 16" version="1.1" width="64"
aria-hidden="true">
<path
d="M15.67 7.06l-1.08-1.34c-.17-.22-.28-.48-.31-.77l-.19-1.7a1.51 1.51 0 0 0-1.33-1.33l-1.7-.19c-.3-.03-.56-.16-.78-.33L8.94.32c-.55-.44-1.33-.44-1.88 0L5.72 1.4c-.22.17-.48.28-.77.31l-1.7.19c-.7.08-1.25.63-1.33 1.33l-.19 1.7c-.03.3-.16.56-.33.78L.32 7.05c-.44.55-.44 1.33 0 1.88l1.08 1.34c.17.22.28.48.31.77l.19 1.7c.08.7.63 1.25 1.33 1.33l1.7.19c.3.03.56.16.78.33l1.34 1.08c.55.44 1.33.44 1.88 0l1.34-1.08c.22-.17.48-.28.77-.31l1.7-.19c.7-.08 1.25-.63 1.33-1.33l.19-1.7c.03-.3.16-.56.33-.78l1.08-1.34c.44-.55.44-1.33 0-1.88zM9 11.5c0 .28-.22.5-.5.5h-1c-.27 0-.5-.22-.5-.5v-1c0-.28.23-.5.5-.5h1c.28 0 .5.22.5.5v1zm1.56-4.89c-.06.17-.17.33-.3.47-.13.16-.14.19-.33.38-.16.17-.31.3-.52.45-.11.09-.2.19-.28.27-.08.08-.14.17-.19.27-.05.1-.08.19-.11.3-.03.11-.03.13-.03.25H7.13c0-.22 0-.31.03-.48.03-.19.08-.36.14-.52.06-.14.14-.28.25-.42.11-.13.23-.25.41-.38.27-.19.36-.3.48-.52.12-.22.2-.38.2-.59 0-.27-.06-.45-.2-.58-.13-.13-.31-.19-.58-.19-.09 0-.19.02-.3.05-.11.03-.17.09-.25.16-.08.07-.14.11-.2.2a.41.41 0 0 0-.09.28h-2c0-.38.13-.56.27-.83.16-.27.36-.5.61-.67.25-.17.55-.3.88-.38.33-.08.7-.13 1.09-.13.44 0 .83.05 1.17.13.34.09.63.22.88.39.23.17.41.38.55.63.13.25.19.55.19.88 0 .22 0 .42-.08.59l-.02-.01z">
@ -33,7 +33,7 @@
</div>
<div class="columns is-desktop is-multiline">
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Output format of the HTML, either line by line or side by side">
<p>Output Format</p>
<select class="options-label-value" id="diff-url-options-output-format" name="outputFormat">
@ -42,14 +42,24 @@
</select>
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Color scheme to render. Auto uses user preference.">
<p>Color Scheme</p>
<select class="options-label-value" id="diff-url-options-color-scheme" name="colorScheme">
<option value="light" selected>Light</option>
<option value="dark">Dark</option>
<option value="auto">Auto</option>
</select>
</label>
</div>
<div class="column is-one-sixth-widescreen">
<label title="Show the file list summary before the diff">
<p>File Summary</p>
<input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="drawFileList"
checked />
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Level of matching for the comparison algorithm">
<p>Matching Type</p>
<select class="options-label-value" id="diff-url-options-matching" name="matching">
@ -59,14 +69,14 @@
</select>
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Similarity threshold for the matching algorithm">
<p>Words Threshold</p>
<input class="options-label-value" id="diff-url-options-match-words-threshold" type="number"
name="matchWordsThreshold" value="0.25" step="0.05" min="0" max="1" />
</label>
</div>
<div class="column is-one-fifth-widescreen">
<div class="column is-one-sixth-widescreen">
<label title="Maximum number of comparison performed by the matching algorithm in a block of changes">
<p>Max Comparisons</p>
<input class="options-label-value" id="diff-url-options-matching-max-comparisons" type="number"
@ -89,7 +99,7 @@
<ul>
<li class="block">
<p class="has-text-weight-bold">Why should I use this instead of GitHub, Bitbucket or GitLab?</p>
<p>There are multiple advantages to using diff2html, but they can be devided in two categories: portability and
<p>There are multiple advantages to using diff2html, but they can be divided in two categories: portability and
features.
</p>
<p>
@ -100,7 +110,7 @@
Regarding features you can have code syntax highlight, line similarity matching (similar lines are together),
line by Line and side by side diffs and easy code selection.
</p>
<p>All of this is completly independent of the provider you use to version the code.</p>
<p>All of this is completely independent of the provider you use to version the code.</p>
</li>
<li class="block">
<p class="has-text-weight-bold">What urls are supported in this demo?</p>
@ -112,7 +122,7 @@
<p>Just copy the url from the page, which should contain all the customizations and reference for the diff you
introduced.</p>
<p>ex: <a
href="demo.html?matching=none&matchWordsThreshold=0.25&maxLineLengthHighlight=10000&diffStyle=word&renderNothingWhenEmpty=0&matchingMaxComparisons=2500&maxLineSizeInBlockForComparison=200&outputFormat=line-by-line&drawFileList=1&synchronisedScroll=1&highlight=1&fileListToggle=1&fileListStartVisible=0&smartSelection=1&diff=https://github.com/rtfpessoa/diff2html/pull/106">https://diff2html.xyz/demo.html?matching=none&matchWordsThreshold=0.25&maxLineLengthHighlight=10000&diffStyle=word&renderNothingWhenEmpty=0&matchingMaxComparisons=2500&maxLineSizeInBlockForComparison=200&outputFormat=line-by-line&drawFileList=1&synchronisedScroll=1&highlight=1&fileListToggle=1&fileListStartVisible=0&smartSelection=1&diff=https://github.com/rtfpessoa/diff2html/pull/106</a>
href="demo.html?matching=none&matchWordsThreshold=0.25&maxLineLengthHighlight=10000&diffStyle=word&renderNothingWhenEmpty=0&matchingMaxComparisons=2500&maxLineSizeInBlockForComparison=200&outputFormat=line-by-line&drawFileList=1&synchronisedScroll=1&highlight=1&fileListToggle=1&fileListStartVisible=0&diff=https://github.com/rtfpessoa/diff2html/pull/106">https://diff2html.xyz/demo.html?matching=none&matchWordsThreshold=0.25&maxLineLengthHighlight=10000&diffStyle=word&renderNothingWhenEmpty=0&matchingMaxComparisons=2500&maxLineSizeInBlockForComparison=200&outputFormat=line-by-line&drawFileList=1&synchronisedScroll=1&highlight=1&fileListToggle=1&fileListStartVisible=0&diff=https://github.com/rtfpessoa/diff2html/pull/106</a>
</p>
</li>
<li class="block">

View file

@ -5,3 +5,21 @@
.diff-url-btn.is-small {
font-size: 0.85rem;
}
.d2h-dark-color-scheme .title {
color: #fff;
}
.d2h-dark-color-scheme .footer {
background-color: #2d2d2d;
}
@media (prefers-color-scheme: dark) {
.d2h-auto-color-scheme .title {
color: #fff;
}
.d2h-auto-color-scheme .footer {
background-color: #2d2d2d;
}
}

View file

@ -2,9 +2,11 @@ import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from '../../
import '../../../main.ts';
import '../../../main.css';
import 'highlight.js/styles/github.css';
import './github-highlights.css';
import '../../../../src/ui/css/diff2html.css';
import './demo.css';
import { colorSchemeToCss } from '../../../../src/render-utils';
import { ColorSchemeType } from '../../../../src/types';
/*
* Example URLs:
@ -21,7 +23,8 @@ import './demo.css';
type URLParams = {
diff?: string;
[key: string]: string | boolean | number | undefined;
diffTooBigMessage?: string;
[key: string]: string | boolean | number | Map<string, string> | undefined;
};
const searchParam = 'diff';
@ -64,11 +67,14 @@ function prepareRequest(url: string): Request {
let fetchUrl;
const headers = new Headers();
const githubCommitUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const githubCommitUrl =
/^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const githubPrUrl = /^https?:\/\/(?:www\.)?github\.com\/(.*?)\/(.*?)\/pull\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const gitlabCommitUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const gitlabPrUrl = /^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/merge_requests\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const gitlabCommitUrl =
/^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/commit\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const gitlabPrUrl =
/^https?:\/\/(?:www\.)?gitlab\.com\/(.*?)\/(.*?)\/merge_requests\/(.*?)(?:\.diff)?(?:\.patch)?(?:\/.*)?$/;
const bitbucketCommitUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/commits\/(.*?)(?:\/raw)?(?:\/.*)?$/;
const bitbucketPrUrl = /^https?:\/\/(?:www\.)?bitbucket\.org\/(.*?)\/(.*?)\/pull-requests\/(.*?)(?:\/.*)?$/;
@ -106,8 +112,7 @@ function prepareRequest(url: string): Request {
} else if ((values = bitbucketPrUrl.exec(url))) {
fetchUrl = bitbucketUrlGen(values[1], values[2], 'pullrequests', values[3]);
} else {
console.info('Could not parse url, using the provided url.');
fetchUrl = 'https://crossorigin.me/' + url;
fetchUrl = url;
}
return {
@ -117,11 +122,17 @@ function prepareRequest(url: string): Request {
}
function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
// Removing `diff` form `urlParams` to avoid being inserted
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { diff, ...urlParamsRest } = urlParams;
// Removing `diff` and `diffTooBigMessage` form `urlParams` to avoid being inserted
const { diff, diffTooBigMessage, ...urlParamsRest } = urlParams;
const defaultColorScheme: ColorSchemeType =
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? ColorSchemeType.DARK
: ColorSchemeType.LIGHT;
const config: URLParams = {
...defaultDiff2HtmlUIConfig,
colorScheme: defaultColorScheme,
...urlParamsRest,
};
@ -129,8 +140,8 @@ function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
const newObject = !Number.isNaN(Number(v))
? { [k]: Number(v) }
: v === 'true' || v === 'false'
? { [k]: Boolean(v) }
: { [k]: v };
? { [k]: Boolean(v) }
: { [k]: v };
return { ...object, ...newObject };
}, {});
}
@ -152,9 +163,16 @@ async function getDiff(request: Request): Promise<string> {
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
const diff2htmlUi = new Diff2HtmlUI(elements.structure.diffTarget, diffString, config);
setBodyColorScheme(diff2htmlUi.config.colorScheme);
diff2htmlUi.draw();
}
function setBodyColorScheme(colorScheme: ColorSchemeType): void {
document.body.className = colorSchemeToCss(colorScheme);
}
async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConfig, string]> {
const urlParams = getParamsFromSearch(window.location.search);
const currentUrl = (urlParams && urlParams[searchParam]) || 'https://github.com/rtfpessoa/diff2html/pull/106';
@ -170,23 +188,21 @@ async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConf
}
function updateBrowserUrl(config: Diff2HtmlUIConfig, newDiffUrl: string): void {
if (history.pushState) {
const paramString = Object.entries(config)
.map(([k, v]) => k + '=' + v)
.join('&');
const newPageUrl =
window.location.protocol +
'//' +
window.location.host +
window.location.pathname +
'?' +
paramString +
'&' +
searchParam +
'=' +
newDiffUrl;
window.history.pushState({ path: newPageUrl }, '', newPageUrl);
}
const paramString = Object.entries(config)
.map(([k, v]) => k + '=' + v)
.join('&');
const newPageUrl =
window.location.protocol +
'//' +
window.location.host +
window.location.pathname +
'?' +
paramString +
'&' +
searchParam +
'=' +
newDiffUrl;
window.history.pushState({ path: newPageUrl }, '', newPageUrl);
}
type Elements = {
@ -199,6 +215,7 @@ type Elements = {
};
options: {
outputFormat: HTMLInputElement;
colorScheme: HTMLInputElement;
matching: HTMLInputElement;
wordsThreshold: HTMLInputElement;
matchingMaxComparisons: HTMLInputElement;
@ -234,6 +251,7 @@ function getHTMLElementById(id: string): HTMLElement {
document.addEventListener('DOMContentLoaded', async () => {
// Improves browser compatibility
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('whatwg-fetch');
const drawAndUpdateUrl = async (
@ -258,6 +276,7 @@ document.addEventListener('DOMContentLoaded', async () => {
},
options: {
outputFormat: getHTMLInputElementById('diff-url-options-output-format'),
colorScheme: getHTMLInputElementById('diff-url-options-color-scheme'),
matching: getHTMLInputElementById('diff-url-options-matching'),
wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'),
matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'),
@ -270,12 +289,13 @@ document.addEventListener('DOMContentLoaded', async () => {
let [config, diffString] = await prepareInitialState(elements);
// Update HTML inputs from any changes in URL
config.outputFormat && (elements.options.outputFormat.value = config.outputFormat);
config.drawFileList && (elements.checkboxes.drawFileList.checked = config.drawFileList);
config.matching && (elements.options.matching.value = config.matching);
config.matchWordsThreshold && (elements.options.wordsThreshold.value = config.matchWordsThreshold.toString());
config.matchingMaxComparisons &&
(elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString());
if (config.outputFormat) elements.options.outputFormat.value = config.outputFormat;
if (config.colorScheme) elements.options.colorScheme.value = config.colorScheme;
if (config.drawFileList) elements.checkboxes.drawFileList.checked = config.drawFileList;
if (config.matching) elements.options.matching.value = config.matching;
if (config.matchWordsThreshold) elements.options.wordsThreshold.value = config.matchWordsThreshold.toString();
if (config.matchingMaxComparisons)
elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString();
Object.entries(elements.options).forEach(([option, element]) =>
element.addEventListener('change', () => {

View file

@ -0,0 +1,332 @@
/*!
Theme Adapted from highlight.js github theme
Theme: Modified GitHub Dark
Description: Dark theme as seen on github.com, modified for diff2html demo
Author: github.com
Maintainer: @Hirse
Updated: 2021-05-15
Outdated base version: https://github.com/primer/github-syntax-dark
Current colors taken from GitHub's CSS
*/
pre code.hljs {
display: block;
overflow-x: auto;
padding: 1em;
}
code.hljs {
padding: 3px 5px;
}
.hljs {
color: #24292e;
}
.hljs-doctag,
.hljs-keyword,
.hljs-meta .hljs-keyword,
.hljs-template-tag,
.hljs-template-variable,
.hljs-type,
.hljs-variable.language_ {
color: #d73a49;
}
.hljs-title,
.hljs-title.class_,
.hljs-title.class_.inherited__,
.hljs-title.function_ {
color: #6f42c1;
}
.hljs-attr,
.hljs-attribute,
.hljs-literal,
.hljs-meta,
.hljs-number,
.hljs-operator,
.hljs-selector-attr,
.hljs-selector-class,
.hljs-selector-id,
.hljs-variable {
color: #005cc5;
}
.hljs-meta .hljs-string,
.hljs-regexp,
.hljs-string {
color: #032f62;
}
.hljs-built_in,
.hljs-symbol {
color: #e36209;
}
.hljs-code,
.hljs-comment,
.hljs-formula {
color: #6a737d;
}
.hljs-name,
.hljs-quote,
.hljs-selector-pseudo,
.hljs-selector-tag {
color: #22863a;
}
.hljs-subst {
color: #24292e;
}
.hljs-section {
color: #005cc5;
font-weight: 700;
}
.hljs-bullet {
color: #735c0f;
}
.hljs-emphasis {
color: #24292e;
font-style: italic;
}
.hljs-strong {
color: #24292e;
font-weight: 700;
}
.hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}
.d2h-dark-color-scheme .hljs {
color: #c9d1d9;
}
.d2h-dark-color-scheme .hljs-doctag,
.d2h-dark-color-scheme .hljs-keyword,
.d2h-dark-color-scheme .hljs-meta .hljs-keyword,
.d2h-dark-color-scheme .hljs-template-tag,
.d2h-dark-color-scheme .hljs-template-variable,
.d2h-dark-color-scheme .hljs-type,
.d2h-dark-color-scheme .hljs-variable.language_ {
color: #ff7b72;
}
.d2h-dark-color-scheme .hljs-title,
.d2h-dark-color-scheme .hljs-title.class_,
.d2h-dark-color-scheme .hljs-title.class_.inherited__,
.d2h-dark-color-scheme .hljs-title.function_ {
color: #d2a8ff;
}
.d2h-dark-color-scheme .hljs-attr,
.d2h-dark-color-scheme .hljs-attribute,
.d2h-dark-color-scheme .hljs-literal,
.d2h-dark-color-scheme .hljs-meta,
.d2h-dark-color-scheme .hljs-number,
.d2h-dark-color-scheme .hljs-operator,
.d2h-dark-color-scheme .hljs-selector-attr,
.d2h-dark-color-scheme .hljs-selector-class,
.d2h-dark-color-scheme .hljs-selector-id,
.d2h-dark-color-scheme .hljs-variable {
color: #79c0ff;
}
.d2h-dark-color-scheme .hljs-meta .hljs-string,
.d2h-dark-color-scheme .hljs-regexp,
.d2h-dark-color-scheme .hljs-string {
color: #a5d6ff;
}
.d2h-dark-color-scheme .hljs-built_in,
.d2h-dark-color-scheme .hljs-symbol {
color: #ffa657;
}
.d2h-dark-color-scheme .hljs-code,
.d2h-dark-color-scheme .hljs-comment,
.d2h-dark-color-scheme .hljs-formula {
color: #8b949e;
}
.d2h-dark-color-scheme .hljs-name,
.d2h-dark-color-scheme .hljs-quote,
.d2h-dark-color-scheme .hljs-selector-pseudo,
.d2h-dark-color-scheme .hljs-selector-tag {
color: #7ee787;
}
.d2h-dark-color-scheme .hljs-subst {
color: #c9d1d9;
}
.d2h-dark-color-scheme .hljs-section {
color: #1f6feb;
font-weight: 700;
}
.d2h-dark-color-scheme .hljs-bullet {
color: #f2cc60;
}
.d2h-dark-color-scheme .hljs-emphasis {
color: #c9d1d9;
font-style: italic;
}
.d2h-dark-color-scheme .hljs-strong {
color: #c9d1d9;
font-weight: 700;
}
.d2h-dark-color-scheme .hljs-addition {
color: #aff5b4;
background-color: #033a16;
}
.d2h-dark-color-scheme .hljs-deletion {
color: #ffdcd7;
background-color: #67060c;
}
@media (prefers-color-scheme: dark) {
.d2h-auto-color-scheme .hljs {
color: #c9d1d9;
}
.d2h-auto-color-scheme .hljs-doctag,
.d2h-auto-color-scheme .hljs-keyword,
.d2h-auto-color-scheme .hljs-meta .hljs-keyword,
.d2h-auto-color-scheme .hljs-template-tag,
.d2h-auto-color-scheme .hljs-template-variable,
.d2h-auto-color-scheme .hljs-type,
.d2h-auto-color-scheme .hljs-variable.language_ {
color: #ff7b72;
}
.d2h-auto-color-scheme .hljs-title,
.d2h-auto-color-scheme .hljs-title.class_,
.d2h-auto-color-scheme .hljs-title.class_.inherited__,
.d2h-auto-color-scheme .hljs-title.function_ {
color: #d2a8ff;
}
.d2h-auto-color-scheme .hljs-attr,
.d2h-auto-color-scheme .hljs-attribute,
.d2h-auto-color-scheme .hljs-literal,
.d2h-auto-color-scheme .hljs-meta,
.d2h-auto-color-scheme .hljs-number,
.d2h-auto-color-scheme .hljs-operator,
.d2h-auto-color-scheme .hljs-selector-attr,
.d2h-auto-color-scheme .hljs-selector-class,
.d2h-auto-color-scheme .hljs-selector-id,
.d2h-auto-color-scheme .hljs-variable {
color: #79c0ff;
}
.d2h-auto-color-scheme .hljs-meta .hljs-string,
.d2h-auto-color-scheme .hljs-regexp,
.d2h-auto-color-scheme .hljs-string {
color: #a5d6ff;
}
.d2h-auto-color-scheme .hljs-built_in,
.d2h-auto-color-scheme .hljs-symbol {
color: #ffa657;
}
.d2h-auto-color-scheme .hljs-code,
.d2h-auto-color-scheme .hljs-comment,
.d2h-auto-color-scheme .hljs-formula {
color: #8b949e;
}
.d2h-auto-color-scheme .hljs-name,
.d2h-auto-color-scheme .hljs-quote,
.d2h-auto-color-scheme .hljs-selector-pseudo,
.d2h-auto-color-scheme .hljs-selector-tag {
color: #7ee787;
}
.d2h-auto-color-scheme .hljs-subst {
color: #c9d1d9;
}
.d2h-auto-color-scheme .hljs-section {
color: #1f6feb;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-bullet {
color: #f2cc60;
}
.d2h-auto-color-scheme .hljs-emphasis {
color: #c9d1d9;
font-style: italic;
}
.d2h-auto-color-scheme .hljs-strong {
color: #c9d1d9;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-addition {
color: #aff5b4;
background-color: #033a16;
}
.d2h-auto-color-scheme .hljs-deletion {
color: #ffdcd7;
background-color: #67060c;
}
}
@media (prefers-color-scheme: light) {
.d2h-auto-color-scheme .hljs {
color: #24292e;
}
.d2h-auto-color-scheme .hljs-doctag,
.d2h-auto-color-scheme .hljs-keyword,
.d2h-auto-color-scheme .hljs-meta .hljs-keyword,
.d2h-auto-color-scheme .hljs-template-tag,
.d2h-auto-color-scheme .hljs-template-variable,
.d2h-auto-color-scheme .hljs-type,
.d2h-auto-color-scheme .hljs-variable.language_ {
color: #d73a49;
}
.d2h-auto-color-scheme .hljs-title,
.d2h-auto-color-scheme .hljs-title.class_,
.d2h-auto-color-scheme .hljs-title.class_.inherited__,
.d2h-auto-color-scheme .hljs-title.function_ {
color: #6f42c1;
}
.d2h-auto-color-scheme .hljs-attr,
.d2h-auto-color-scheme .hljs-attribute,
.d2h-auto-color-scheme .hljs-literal,
.d2h-auto-color-scheme .hljs-meta,
.d2h-auto-color-scheme .hljs-number,
.d2h-auto-color-scheme .hljs-operator,
.d2h-auto-color-scheme .hljs-selector-attr,
.d2h-auto-color-scheme .hljs-selector-class,
.d2h-auto-color-scheme .hljs-selector-id,
.d2h-auto-color-scheme .hljs-variable {
color: #005cc5;
}
.d2h-auto-color-scheme .hljs-meta .hljs-string,
.d2h-auto-color-scheme .hljs-regexp,
.d2h-auto-color-scheme .hljs-string {
color: #032f62;
}
.d2h-auto-color-scheme .hljs-built_in,
.d2h-auto-color-scheme .hljs-symbol {
color: #e36209;
}
.d2h-auto-color-scheme .hljs-code,
.d2h-auto-color-scheme .hljs-comment,
.d2h-auto-color-scheme .hljs-formula {
color: #6a737d;
}
.d2h-auto-color-scheme .hljs-name,
.d2h-auto-color-scheme .hljs-quote,
.d2h-auto-color-scheme .hljs-selector-pseudo,
.d2h-auto-color-scheme .hljs-selector-tag {
color: #22863a;
}
.d2h-auto-color-scheme .hljs-subst {
color: #24292e;
}
.d2h-auto-color-scheme .hljs-section {
color: #005cc5;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-bullet {
color: #735c0f;
}
.d2h-auto-color-scheme .hljs-emphasis {
color: #24292e;
font-style: italic;
}
.d2h-auto-color-scheme .hljs-strong {
color: #24292e;
font-weight: 700;
}
.d2h-auto-color-scheme .hljs-addition {
color: #22863a;
background-color: #f0fff4;
}
.d2h-auto-color-scheme .hljs-deletion {
color: #b31d28;
background-color: #ffeef0;
}
}

View file

@ -72,7 +72,7 @@
<span class="button clipboard" data-clipboard-text="npm install diff2html" title="Copy">Copy</span>
</div>
<p>
<a href="https://github.com/rtfpessoa/diff2html#how-to-use" target="_blank" rel="noopener" rel="noreferrer">
<a href="https://github.com/rtfpessoa/diff2html#usage" target="_blank" rel="noopener" rel="noreferrer">
Find usage examples in the Docs
</a>
</p>
@ -85,8 +85,8 @@
<div class="column">
<h4 class="title is-size-4 is-spaced"><strong>With command line integration</strong></h4>
<p>We work hard to make sure you can have your diffs in a simple and flexible
way. Go here for the <a href="https://github.com/rtfpessoa/diff2html-cli" target="_blank"
rel="noopener" rel="noreferrer"></a>full
way. Go here for the <a href="https://github.com/rtfpessoa/diff2html-cli#readme" target="_blank"
rel="noopener" rel="noreferrer">full
documentation</a>.
</p>
</div>
@ -115,8 +115,46 @@
<hr>
<div id="users" class="container">
<h4 class="title is-size-4 is-spaced"><strong>Projects using diff2html</strong></h4>
<h4 class="title is-size-4 is-spaced"><strong>Sponsor</strong></h4>
<div class="columns is-desktop is-multiline">
<div class="column is-half-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<div class="flex">
<div class="flex">
<img src="https://huggingface.co/front/assets/huggingface_logo-noborder.svg" style="height: 30px;">
<div>
<div style="margin-left: 5px;" class="is-size-5 has-text-weight-bold flex">Hugging Face</div>
</div>
</header>
<section class="media-content">
<p>The AI community building the future. Build, train and deploy state of the art models powered by the reference open source in natural language processing.</p>
</section>
<footer>
<a href="https://huggingface.co/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
</div>
<h4 class="title is-size-4 is-spaced"><strong>Other projects using diff2html</strong></h4>
<div class="columns is-desktop is-multiline">
<div class="column is-one-quarter-widescreen is-flex" style="min-height: 166px;">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Exercism</p>
</header>
<section class="media-content">
<p>Get really good at programming.</p>
</section>
<footer>
<a href="https://exercism.org/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
@ -131,19 +169,21 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Codacy</p>
</header>
<section class="media-content">
<p>Check code style, security, duplication, complexity and coverage on every change.</p>
<p>Automate code reviews on your commits and pull requests.</p>
</section>
<footer>
<a href="https://www.codacy.com" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
@ -158,6 +198,7 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
@ -171,6 +212,7 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
@ -180,91 +222,12 @@
<p>Show diffs between builds</p>
</section>
<footer>
<a href="https://wiki.jenkins-ci.org/display/JENKINS/Last+Changes+Plugin" target="_blank"
<a href="https://plugins.jenkins.io/last-changes/" target="_blank"
rel="noopener" rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">jest-stare</p>
</header>
<section class="media-content">
<p>Jest HTML Reporter and Results Processor.</p>
</section>
<footer>
<a href="https://dkelosky.github.io/jest-stare/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">kubeapps</p>
</header>
<section class="media-content">
<p>A web-based UI for deploying and managing applications in Kubernetes clusters.</p>
</section>
<footer>
<a href="https://kubeapps.com/" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Hitchhiker</p>
</header>
<section class="media-content">
<p>A a Restful Api test tool.</p>
</section>
<footer>
<a href="http://www.hitchhiker-api.com/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">growi</p>
</header>
<section class="media-content">
<p>Team collaboration software using markdown.</p>
</section>
<footer>
<a href="https://growi.org/" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">crowi</p>
</header>
<section class="media-content">
<p>Markdown Wiki - Empower the team with sharing your knowledge.</p>
</section>
<footer>
<a href="http://site.crowi.wiki/" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Wiki.js</p>
</header>
<section class="media-content">
<p>A modern, lightweight and powerful wiki app built on Node.js.</p>
</section>
<footer>
<a href="https://wiki.js.org/" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
@ -279,41 +242,28 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Chef Automate</p>
</header>
<section class="media-content">
<p>full suite of enterprise capabilities for maintaining continuous visibility into application,
infrastructure, and security automation.</p>
<p>DevOps Dashboard for Complete Operational Visibility.</p>
</section>
<footer>
<a href="https://automate.chef.io/" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Camunda Modeler</p>
<p class="is-size-5 has-text-weight-bold">GraphQL Schema Diff</p>
</header>
<section class="media-content">
<p>An integrated modeling solution for BPMN, DMN and CMMN based on bpmn.io.</p>
</section>
<footer>
<a href="https://camunda.com/products/modeler" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">graphql-schema-diff</p>
</header>
<section class="media-content">
<p>Returns the diff of two GraphQL schemas. Detects dangerous and breaking changes.</p>
<p>Detects dangerous and breaking changes in GraphQL schemas.</p>
</section>
<footer>
<a href="https://github.com/fabsrc/graphql-schema-diff" target="_blank" rel="noopener"
@ -321,13 +271,14 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">cypress-plugin-snapshots</p>
</header>
<section class="media-content">
<p>Plugin for snapshot tests in Cypress.io .</p>
<p>Plugin for snapshot tests in Cypress.io.</p>
</section>
<footer>
<a href="https://github.com/meinaart/cypress-plugin-snapshots" target="_blank" rel="noopener"
@ -335,13 +286,14 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">git-explorer</p>
</header>
<section class="media-content">
<p>Offline-first support for previewing and comparing branches in a local git repository.</p>
<p>Offline-first support for previewing local git repositories.</p>
</section>
<footer>
<a href="https://github.com/thescientist13/git-explorer" target="_blank" rel="noopener"
@ -349,34 +301,7 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">diff-pane</p>
</header>
<section class="media-content">
<p>Atom - Diff two panes.</p>
</section>
<footer>
<a href="https://github.com/t-ari/diff-pane" target="_blank" rel="noopener"
rel="noreferrer">View GitHub</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">node-giff</p>
</header>
<section class="media-content">
<p>Display git diff on browser.</p>
</section>
<footer>
<a href="https://github.com/do7be/node-giff" target="_blank" rel="noopener"
rel="noreferrer">View GitHub</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
@ -391,20 +316,7 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">node-git</p>
</header>
<section class="media-content">
<p>Execute Git Command by Node.js.</p>
</section>
<footer>
<a href="https://github.com/liangshuai/node-git" target="_blank" rel="noopener"
rel="noreferrer">View GitHub</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
@ -419,6 +331,171 @@
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">jsreport</p>
</header>
<section class="media-content">
<p>javascript based business reporting platform</p>
</section>
<footer>
<a href="https://jsreport.net" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">dendron</p>
</header>
<section class="media-content">
<p>Knowledge Management. Redefined.</p>
</section>
<footer>
<a href="https://www.dendron.so" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">jest-stare</p>
</header>
<section class="media-content">
<p>Jest HTML Reporter and Results Processor</p>
</section>
<footer>
<a href="https://dkelosky.github.io/jest-stare/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Wiki.js</p>
</header>
<section class="media-content">
<p>The most powerful and extensible open source Wiki software</p>
</section>
<footer>
<a href="https://js.wiki/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Salto</p>
</header>
<section class="media-content">
<p>Understand Your Business Apps' Configuration</p>
</section>
<footer>
<a href="https://www.salto.io/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">intuit Design Systems CLI</p>
</header>
<section class="media-content">
<p>A CLI toolbox for creating design systems</p>
</section>
<footer>
<a href="https://intuit.github.io/design-systems-cli/#/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Camunda Modeler</p>
</header>
<section class="media-content">
<p>Automate processes and decisions in a modern, standards-based way</p>
</section>
<footer>
<a href="https://camunda.com/download/modeler/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">igit</p>
</header>
<section class="media-content">
<p>Tool for managing pull requests</p>
</section>
<footer>
<a href="https://igit.dev/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Crowi</p>
</header>
<section class="media-content">
<p>Empower the team with sharing your knowledge</p>
</section>
<footer>
<a href="https://site.crowi.wiki/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">Robusta</p>
</header>
<section class="media-content">
<p>Open source Kubernetes troubleshooting and automation platform</p>
</section>
<footer>
<a href="https://docs.robusta.dev/master/" target="_blank" rel="noopener"
rel="noreferrer">Website</a>
</footer>
</div>
</div>
<div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical">
<header>
<p class="is-size-5 has-text-weight-bold">git-tabular-diff</p>
</header>
<section class="media-content">
<p>Displays a tabular difference of a csv file or a split difference of any file in an Atom pane</p>
</section>
<footer>
<a href="https://github.com/jstritch/git-tabular-diff" target="_blank" rel="noopener"
rel="noreferrer">View GitHub</a>
</footer>
</div>
</div>
</div>
</div>
@ -433,7 +510,7 @@
<a href="https://gitter.im/rtfpessoa/diff2html" target="_blank" rel="noopener" rel="noreferrer">Gitter</a>.
Need any help?
</p>
<a href="https://github.com/rtfpessoa/diff2html#how-to-use" target="_blank" rel="noopener" rel="noreferrer">
<a href="https://github.com/rtfpessoa/diff2html#usage" target="_blank" rel="noopener" rel="noreferrer">
Read more in the Docs
</a>
</div>

View file

@ -8,7 +8,11 @@
}
.hero-booticon {
font-family: Helvetica Neue, Helvetica, Arial, sans-serif;
font-family:
Helvetica Neue,
Helvetica,
Arial,
sans-serif;
margin: 0 auto 30px;
width: 100%;
font-size: 8vw;
@ -42,6 +46,12 @@
cursor: pointer;
}
.flex {
display: flex;
flex-direction: row;
justify-content: flex-start;
}
.is-fullwidth {
flex-grow: 1;
}
@ -49,3 +59,7 @@
.is-vertical {
flex-direction: column;
}
.align-middle {
vertical-align: middle;
}

View file

@ -4,5 +4,4 @@ import '../../../main.ts';
import '../../../main.css';
import './index.css';
// eslint-disable-next-line no-new
new Clipboard(document.getElementsByClassName('clipboard')[0]);

View file

@ -78,7 +78,7 @@
<a href="https://twitter.com/rtfpessoa" target="_blank" rel="noopener" rel="noreferrer">@rtfpessoa</a>.
</p>
<p>
<a class="footer-list-link" href="https://github.com/rtfpessoa/diff2html#how-to-use" target="_blank"
<a class="footer-list-link" href="https://github.com/rtfpessoa/diff2html#usage" target="_blank"
rel="noopener" rel="noreferrer">FAQ</a>
-
<a class="footer-list-link" href="https://diff2html.xyz">diff2html</a>

10814
yarn.lock

File diff suppressed because it is too large Load diff