Compare commits

...

194 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
55 changed files with 22493 additions and 10283 deletions

View file

@ -52,7 +52,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/8504000?v=4", "avatar_url": "https://avatars0.githubusercontent.com/u/8504000?v=4",
"profile": "http://heyitsmattwade.com", "profile": "http://heyitsmattwade.com",
"contributions": [ "contributions": [
"bug" "bug",
"code"
] ]
}, },
{ {
@ -79,7 +80,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/1567423?v=4", "avatar_url": "https://avatars0.githubusercontent.com/u/1567423?v=4",
"profile": "https://saino.me/", "profile": "https://saino.me/",
"contributions": [ "contributions": [
"bug" "bug",
"code"
] ]
}, },
{ {
@ -97,7 +99,8 @@
"avatar_url": "https://avatars2.githubusercontent.com/u/7767299?v=4", "avatar_url": "https://avatars2.githubusercontent.com/u/7767299?v=4",
"profile": "http://wesssel.github.io/", "profile": "http://wesssel.github.io/",
"contributions": [ "contributions": [
"security" "security",
"code"
] ]
}, },
{ {
@ -115,7 +118,8 @@
"avatar_url": "https://avatars1.githubusercontent.com/u/1446970?v=4", "avatar_url": "https://avatars1.githubusercontent.com/u/1446970?v=4",
"profile": "https://github.com/sss0791", "profile": "https://github.com/sss0791",
"contributions": [ "contributions": [
"bug" "bug",
"code"
] ]
}, },
{ {
@ -124,7 +128,8 @@
"avatar_url": "https://avatars3.githubusercontent.com/u/4741620?v=4", "avatar_url": "https://avatars3.githubusercontent.com/u/4741620?v=4",
"profile": "http://researcher.watson.ibm.com/researcher/view.php?person=us-nickm", "profile": "http://researcher.watson.ibm.com/researcher/view.php?person=us-nickm",
"contributions": [ "contributions": [
"bug" "bug",
"code"
] ]
}, },
{ {
@ -142,7 +147,8 @@
"avatar_url": "https://avatars3.githubusercontent.com/u/8926560?v=4", "avatar_url": "https://avatars3.githubusercontent.com/u/8926560?v=4",
"profile": "https://twitter.com/pubkeypubkey", "profile": "https://twitter.com/pubkeypubkey",
"contributions": [ "contributions": [
"doc" "doc",
"code"
] ]
}, },
{ {
@ -160,7 +166,9 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/1823771?v=4", "avatar_url": "https://avatars0.githubusercontent.com/u/1823771?v=4",
"profile": "https://akr.am", "profile": "https://akr.am",
"contributions": [ "contributions": [
"bug" "bug",
"doc",
"code"
] ]
}, },
{ {
@ -178,7 +186,8 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/8316?v=4", "avatar_url": "https://avatars0.githubusercontent.com/u/8316?v=4",
"profile": "http://twitter.com/dimasabanin", "profile": "http://twitter.com/dimasabanin",
"contributions": [ "contributions": [
"maintenance" "maintenance",
"code"
] ]
}, },
{ {
@ -196,7 +205,8 @@
"avatar_url": "https://avatars1.githubusercontent.com/u/2196373?v=4", "avatar_url": "https://avatars1.githubusercontent.com/u/2196373?v=4",
"profile": "http://webminer.js.org", "profile": "http://webminer.js.org",
"contributions": [ "contributions": [
"bug" "bug",
"doc"
] ]
}, },
{ {
@ -223,7 +233,6 @@
"avatar_url": "https://avatars0.githubusercontent.com/u/1155220?v=4", "avatar_url": "https://avatars0.githubusercontent.com/u/1155220?v=4",
"profile": "https://github.com/escitalopram", "profile": "https://github.com/escitalopram",
"contributions": [ "contributions": [
"bug",
"code" "code"
] ]
}, },
@ -245,6 +254,88 @@
"contributions": [ "contributions": [
"code" "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 "contributorsPerLine": 7

View file

@ -1,228 +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: &build-common
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 install --ignore-engines
- save_cache:
key: yarn-cache-{{ checksum "yarn.lock" }}
paths:
- /usr/local/share/.cache/yarn
- run:
name: Build templates
command: yarn run build:templates
- run:
name: Build library
command: yarn run build
build-stable: &build-stable
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:
name: Validate & Build
command: 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-12:
<<: *build-common
docker:
- image: node:12
build-node-15:
<<: *build-common
docker:
- image: node:15
build-node-14:
<<: *build-stable
docker:
- image: node:14
tag_version:
docker:
- image: node:14
working_directory: ~/workdir
steps:
- attach_workspace:
at: ~/workdir
- run:
name: Configure Git
command: |
git config user.email "circleci@users.noreply.github.com"
git config user.name "CircleCI"
- run:
name: Tag version
command: |
git tag "$(cat .version)"
git push --tags "https://rtfpessoa:$GPR_AUTH_TOKEN@github.com/rtfpessoa/diff2html"
publish_library:
docker:
- image: node:14
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)
- 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:
image: ubuntu-1604:202004-01
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-12:
requires:
- checkout-and-version
- build-node-14:
requires:
- checkout-and-version
- build-node-15:
requires:
- checkout-and-version
- publish_approval:
type: approval
requires:
- build-node-12
- build-node-14
- build-node-15
- tag_version:
requires:
- publish_approval
- publish_library:
requires:
- tag_version
- publish_website:
requires:
- tag_version
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',
],
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',
// Too verbose
'sonarjs/no-nested-template-literals': '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

View file

@ -1,51 +0,0 @@
name: "Code scanning - action"
on:
push:
pull_request:
schedule:
- cron: '0 19 * * 1'
jobs:
CodeQL-Build:
runs-on: ubuntu-latest
steps:
- name: Checkout repository
uses: actions/checkout@v2
with:
# We must fetch at least the immediate parents so that if this is
# a pull request then we can checkout the head.
fetch-depth: 2
# If this run was triggered by a pull request event, then checkout
# the head of the pull request instead of the merge commit.
- run: git checkout HEAD^2
if: ${{ github.event_name == 'pull_request' }}
# Initializes the CodeQL tools for scanning.
- name: Initialize CodeQL
uses: github/codeql-action/init@v1
# Override language selection by uncommenting this and choosing your languages
# with:
# languages: go, javascript, csharp, python, cpp, java
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
# If this step fails, then you should remove it and run the build manually (see below)
- name: Autobuild
uses: github/codeql-action/autobuild@v1
# Command-line programs to run using the OS shell.
# 📚 https://git.io/JvXDl
# ✏️ If the Autobuild fails above, remove it and uncomment the following three lines
# and modify them (or add more) to build your code if your project
# uses a compiled language
#- run: |
# make bootstrap
# make release
- name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v1

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/.terraform /terraform/.terraform
/_target/ # Compiled templates
/src/diff2html-templates.* /src/diff2html-templates.*
# Compiled website
/docs/ /docs/
# Bundles temporary typescript files compiled by webpack
/bundles-out/
# Web bundles
/bundles/ /bundles/
# CommonJS library
/lib/ /lib/
# ESNext library
/lib-esm/ /lib-esm/

View file

@ -1,4 +1,3 @@
#!/bin/sh #!/bin/sh
. "$(dirname "$0")/_/husky.sh"
npx lint-staged npm run lint:staged

View file

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

View file

@ -10,9 +10,9 @@
- Before sending a pull request make sure your code is tested. - 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. - Use `git rebase` (not `git merge`) to sync your work from time to time with the master branch.

164
README.md
View file

@ -1,23 +1,20 @@
# diff2html # 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) [![npm](https://img.shields.io/npm/v/diff2html)](https://www.npmjs.com/package/diff2html)
[![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) [![node](https://img.shields.io/node/v/diff2html)](https://www.npmjs.com/package/diff2html)
[![CircleCI](https://circleci.com/gh/rtfpessoa/diff2html.svg?style=svg)](https://circleci.com/gh/rtfpessoa/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 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)
[![npm](https://img.shields.io/npm/v/diff2html?style=flat)](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)
[![jsdelivr CDN Downloads](https://data.jsdelivr.com/v1/package/npm/diff2html/badge)](https://www.jsdelivr.com/package/npm/diff2html) [![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)
[![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)
diff2html generates pretty HTML diffs from git diff or unified diff output. 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 ## Table of Contents
<!-- toc --> <!-- toc -->
@ -156,6 +153,7 @@ draw(): void
synchronisedScroll(): void synchronisedScroll(): void
fileListToggle(startVisible: boolean): void fileListToggle(startVisible: boolean): void
highlightCode(): void highlightCode(): void
stickyFileHeaders(): void
``` ```
### Diff2HtmlUI Configuration ### Diff2HtmlUI Configuration
@ -165,6 +163,7 @@ highlightCode(): void
- `fileListToggle`: allow the file summary list to be toggled: `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` - `fileListStartVisible`: choose if the file summary list starts visible: `true` or `false`, default is `false`
- `fileContentToggle`: allow each file contents to be toggled: `true` or `false`, default is `true` - `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 - [All the options](#diff2html-configuration) from Diff2Html are also valid configurations in Diff2HtmlUI
### Diff2HtmlUI Browser ### Diff2HtmlUI Browser
@ -202,7 +201,7 @@ diff2htmlUi.draw();
```html ```html
<!-- Stylesheet --> <!-- Stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.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" /> <link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
<!-- Javascripts --> <!-- Javascripts -->
@ -228,6 +227,21 @@ document.addEventListener('DOMContentLoaded', () => {
}); });
``` ```
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 #### Collapsable File Summary List
> Add the dependencies. > Add the dependencies.
@ -254,7 +268,7 @@ document.addEventListener('DOMContentLoaded', () => {
#### Example with plain HTML+CSS+JS #### Example with plain HTML+CSS+JS
```html ```html
<!DOCTYPE html> <!doctype html>
<html lang="en-us"> <html lang="en-us">
<head> <head>
<meta charset="utf-8" /> <meta charset="utf-8" />
@ -269,12 +283,12 @@ document.addEventListener('DOMContentLoaded', () => {
</head> </head>
<script> <script>
const diffString = `diff --git a/sample.js b/sample.js const diffString = `diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba index 0000001..0ddf2ba
--- a/sample.js --- a/sample.js
+++ b/sample.js +++ b/sample.js
@@ -1 +1 @@ @@ -1 +1 @@
-console.log("Hello World!") -console.log("Hello World!")
+console.log("Hello from Diff2Html!")`; +console.log("Hello from Diff2Html!")`;
document.addEventListener('DOMContentLoaded', function () { document.addEventListener('DOMContentLoaded', function () {
var targetElement = document.getElementById('myDiffElement'); var targetElement = document.getElementById('myDiffElement');
@ -300,6 +314,41 @@ document.addEventListener('DOMContentLoaded', () => {
</html> </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 Usage
### Diff2Html API ### Diff2Html API
@ -341,7 +390,7 @@ The HTML output accepts a Javascript object with configuration. Possible options
`false` `false`
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is - `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is
`2500` `2500`
- `maxLineSizeInBlockForComparison`: maximum number os characters of the bigger line in a block to apply comparison, - `maxLineSizeInBlockForComparison`: maximum number of characters of the bigger line in a block to apply comparison,
default is `200` default is `200`
- `compiledTemplates`: object ([Hogan.js](https://github.com/twitter/hogan.js/) template values) with previously - `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: compiled templates to replace parts of the html, default is `{}`. For example:
@ -350,6 +399,10 @@ The HTML output accepts a Javascript object with configuration. Possible options
For example: `{ "tag-file-changed": "<span class="d2h-tag d2h-changed d2h-changed-tag">MODIFIED</span>" }` 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 > For more information regarding the possible templates look into
> [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates) > [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 ### Diff2Html Browser
@ -417,7 +470,7 @@ export class AppDiffComponent implements OnInit {
- HTML - HTML
```html ```html
<!DOCTYPE html> <!doctype html>
<html> <html>
<head> <head>
<title>diff2html</title> <title>diff2html</title>
@ -494,42 +547,53 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- markdownlint-disable --> <!-- markdownlint-disable -->
<table> <table>
<tr> <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://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" 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/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" 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="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" 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://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" 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://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" 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="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" 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://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>
<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="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" 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://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" 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="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" 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://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" 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="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" 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="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" 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://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>
<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://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" 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://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" 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://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" 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="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" 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="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" 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="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" 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="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>
<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/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" 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/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" 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/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" 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="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" 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="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> </tr>
</table> </table>
<!-- markdownlint-enable --> <!-- markdownlint-restore -->
<!-- prettier-ignore-end --> <!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST: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, 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

@ -35,35 +35,35 @@
"node": ">=12" "node": ">=12"
}, },
"scripts": { "scripts": {
"eslint": "eslint --ignore-path .gitignore \"**/*.{js,jsx,ts,tsx,json}\"", "lint:staged": "lint-staged",
"lint:check": "yarn run eslint", "lint:check": "eslint",
"lint:fix": "yarn run eslint --fix", "lint:fix": "eslint --fix",
"prettier": "prettier --ignore-path .gitignore '**/*.+(js|jsx|ts|tsx|json|css|html|md|mdx)'", "prettier": "prettier --ignore-path .gitignore '**/*.+(js|jsx|ts|tsx|json|css|html|md|mdx)'",
"format:check": "yarn run prettier --check", "format:check": "npm run prettier --check",
"format:fix": "yarn run prettier --write", "format:fix": "npm 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": "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:es5": "rm -rf lib; tsc -p tsconfig.json --outDir lib", "build:commonjs": "rm -rf lib; tsc -p tsconfig.json -m CommonJS --outDir lib",
"build:esm": "rm -rf lib-esm; tsc -p tsconfig.json -m es6 --outDir lib-esm", "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: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: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:templates": "ts-node ./scripts/hulk.ts --wrapper ts --variable 'defaultTemplates' ./src/templates/*.mustache > ./src/diff2html-templates.ts",
"build:website": "rm -rf docs; webpack --mode production --config webpack.website.ts", "build:website": "rm -rf docs; webpack --mode production --config webpack.website.ts",
"gen": "yarn run gen:toc", "gen": "npm run gen:toc",
"gen:toc-base": "markdown-toc --maxdepth 3 --bullets='-' -i", "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": "is-ci 'test:coverage' 'test:watch'",
"test:coverage": "jest --coverage", "test:coverage": "jest --coverage",
"test:watch": "jest --watch", "test:watch": "jest --watch",
"test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand --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:open": "npm run test:coverage && open ./coverage/index.html",
"coverage:push": "curl -Ls https://coverage.codacy.com/get.sh | bash", "coverage:push": "curl -Ls https://coverage.codacy.com/get.sh | bash",
"validate": "yarn run build:templates && yarn run format:check && yarn run lint:check && yarn run build && yarn run test:coverage", "validate": "npm run build:templates && npm run format:check && npm run lint:check && npm run build && npm run test:coverage",
"fix": "yarn run format:fix && yarn run lint:fix", "fix": "npm run format:fix && npm run lint:fix",
"start": "yarn run start:website", "start": "npm run start:website",
"start:website": "webpack-dev-server --mode development --config webpack.website.ts", "start:website": "webpack serve --mode development --config webpack.website.ts",
"preversion": "yarn run validate", "preversion": "npm run validate",
"version": "git add -A package.json", "version": "git add -A package.json",
"prepare": "husky install" "prepare": "husky"
}, },
"main": "./lib/diff2html.js", "main": "./lib/diff2html.js",
"module": "./lib-esm/diff2html.js", "module": "./lib-esm/diff2html.js",
@ -77,69 +77,65 @@
"prettier --write" "prettier --write"
], ],
"README.md": [ "README.md": [
"yarn run gen:toc-base" "npm run gen:toc-base"
] ]
}, },
"dependencies": { "dependencies": {
"diff": "5.0.0", "diff": "^7.0.0",
"hogan.js": "3.0.2" "hogan.js": "3.0.2"
}, },
"optionalDependencies": { "optionalDependencies": {
"highlight.js": "11.1.0" "highlight.js": "11.9.0"
}, },
"devDependencies": { "devDependencies": {
"@types/copy-webpack-plugin": "8.0.1", "prettier-2": "npm:prettier@^2",
"@types/diff": "5.0.1", "@eslint/js": "^9.17.0",
"@types/hogan.js": "3.0.1", "@eslint/json": "^0.9.0",
"@types/jest": "26.0.24", "@types/diff": "^6.0.0",
"@types/mini-css-extract-plugin": "^2.0.1", "@types/hogan.js": "3.0.5",
"@types/mkdirp": "1.0.2", "@types/jest": "^29.5.14",
"@types/node": "16.4.1", "@types/node": "^22.10.2",
"@types/nopt": "3.0.29", "@types/nopt": "3.0.32",
"@typescript-eslint/eslint-plugin": "4.28.4", "all-contributors-cli": "^6.24.0",
"@typescript-eslint/parser": "4.28.4", "autoprefixer": "^10.4.20",
"autoprefixer": "10.3.1", "bulma": "^1.0.2",
"bulma": "^0.9.2", "clipboard": "2.0.11",
"clipboard": "2.0.8", "copy-webpack-plugin": "^12.0.2",
"copy-webpack-plugin": "9.0.1", "css-loader": "^7.1.2",
"css-loader": "6.2.0", "cssnano": "^7.0.6",
"cssnano": "5.0.7", "eslint": "^9.17.0",
"eslint": "7.31.0", "eslint-plugin-jest": "28.10.0",
"eslint-config-prettier": "8.3.0", "eslint-plugin-promise": "^7.2.1",
"eslint-plugin-import": "2.23.4",
"eslint-plugin-jest": "24.4.0",
"eslint-plugin-json": "3.0.0",
"eslint-plugin-node": "11.1.0",
"eslint-plugin-optimize-regex": "1.2.0",
"eslint-plugin-promise": "5.1.0",
"eslint-plugin-sonarjs": "0.9.1",
"file-loader": "6.2.0", "file-loader": "6.2.0",
"handlebars": "4.7.7", "globals": "^15.14.0",
"handlebars-loader": "1.7.1", "handlebars": "4.7.8",
"html-webpack-plugin": "5.3.2", "handlebars-loader": "1.7.3",
"husky": "^7.0.1", "html-webpack-plugin": "^5.6.3",
"image-webpack-loader": "7.0.1", "husky": "^9.1.7",
"image-webpack-loader": "8.1.0",
"is-ci-cli": "2.2.0", "is-ci-cli": "2.2.0",
"jest": "27.0.6", "jest": "29.7.0",
"lint-staged": "11.1.0", "lint-staged": "^15.2.11",
"markdown-toc": "^1.2.0", "markdown-toc": "^1.2.0",
"mini-css-extract-plugin": "2.1.0", "mini-css-extract-plugin": "^2.9.2",
"mkdirp": "1.0.4", "mkdirp": "3.0.1",
"nopt": "5.0.0", "nopt": "^8.0.0",
"postcss": "8.3.6", "postcss": "^8.4.49",
"postcss-cli": "8.3.1", "postcss-cli": "11.0.0",
"postcss-import": "14.0.2", "postcss-import": "^16.1.0",
"postcss-loader": "6.1.1", "postcss-loader": "^8.1.1",
"postcss-preset-env": "6.7.0", "postcss-preset-env": "^10.1.2",
"prettier": "2.3.2", "prettier": "^3.4.2",
"ts-jest": "27.0.4", "ts-jest": "^29.2.5",
"ts-loader": "9.2.3", "ts-loader": "9.5.1",
"ts-node": "10.1.0", "ts-node": "10.9.2",
"typescript": "4.3.5", "typescript": "^5.7.2",
"typescript-eslint": "^8.18.2",
"url-loader": "4.1.1", "url-loader": "4.1.1",
"webpack": "5.46.0", "webpack": "^5.97.1",
"webpack-cli": "4.7.2", "webpack-cli": "^6.0.1",
"whatwg-fetch": "3.6.2" "webpack-dev-server": "^5.2.0",
"whatwg-fetch": "3.6.20"
}, },
"resolutions": { "resolutions": {
"lodash": ">=4.17.20", "lodash": ">=4.17.20",
@ -148,7 +144,12 @@
"autolinker": ">=3.14.1", "autolinker": ">=3.14.1",
"bl": ">=2.2.1", "bl": ">=2.2.1",
"decompress": ">=4.2.1", "decompress": ">=4.2.1",
"node-forge": ">=0.10.0" "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", "license": "MIT",
"files": [ "files": [

View file

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

File diff suppressed because it is too large Load diff

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(` expect(result).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
File without changes File without changes
</div> </div>
</td> </td>

View file

@ -11,8 +11,8 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.generateEmptyDiff(); const fileHtml = lineByLineRenderer.generateEmptyDiff();
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
File without changes File without changes
</div> </div>
</td> </td>
@ -23,9 +23,19 @@ describe('LineByLineRenderer', () => {
describe('makeLineHtml', () => { describe('makeLineHtml', () => {
it('should work for insertions', () => { 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 hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {}); const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({ const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS, type: CSSLineClass.INSERTS,
prefix: '+', prefix: '+',
content: 'test', content: 'test',
@ -34,14 +44,14 @@ describe('LineByLineRenderer', () => {
}); });
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\"> <td class="d2h-code-linenumber d2h-ins">
<div class=\\"line-num1\\"></div> <div class="line-num1"></div>
<div class=\\"line-num2\\">30</div> <div class="line-num2">30</div>
</td> </td>
<td class=\\"d2h-ins\\"> <td class="d2h-ins">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\">test</span> <span class="d2h-code-line-ctn">test</span>
</div> </div>
</td> </td>
</tr>" </tr>"
@ -49,9 +59,19 @@ describe('LineByLineRenderer', () => {
}); });
it('should work for deletions', () => { 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 hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {}); const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({ const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.DELETES, type: CSSLineClass.DELETES,
prefix: '-', prefix: '-',
content: 'test', content: 'test',
@ -60,14 +80,14 @@ describe('LineByLineRenderer', () => {
}); });
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-code-linenumber d2h-del\\"> <td class="d2h-code-linenumber d2h-del">
<div class=\\"line-num1\\">30</div> <div class="line-num1">30</div>
<div class=\\"line-num2\\"></div> <div class="line-num2"></div>
</td> </td>
<td class=\\"d2h-del\\"> <td class="d2h-del">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">-</span> <span class="d2h-code-line-prefix">-</span>
<span class=\\"d2h-code-line-ctn\\">test</span> <span class="d2h-code-line-ctn">test</span>
</div> </div>
</td> </td>
</tr>" </tr>"
@ -75,9 +95,19 @@ describe('LineByLineRenderer', () => {
}); });
it('should convert indents into non breakin spaces (2 white spaces)', () => { 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 hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {}); const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({ const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS, type: CSSLineClass.INSERTS,
prefix: '+', prefix: '+',
content: ' test', content: ' test',
@ -86,14 +116,14 @@ describe('LineByLineRenderer', () => {
}); });
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\"> <td class="d2h-code-linenumber d2h-ins">
<div class=\\"line-num1\\"></div> <div class="line-num1"></div>
<div class=\\"line-num2\\">30</div> <div class="line-num2">30</div>
</td> </td>
<td class=\\"d2h-ins\\"> <td class="d2h-ins">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"> test</span> <span class="d2h-code-line-ctn"> test</span>
</div> </div>
</td> </td>
</tr>" </tr>"
@ -101,9 +131,19 @@ describe('LineByLineRenderer', () => {
}); });
it('should convert indents into non breakin spaces (4 white spaces)', () => { 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 hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {}); const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({ const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS, type: CSSLineClass.INSERTS,
prefix: '+', prefix: '+',
content: ' test', content: ' test',
@ -112,14 +152,14 @@ describe('LineByLineRenderer', () => {
}); });
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\"> <td class="d2h-code-linenumber d2h-ins">
<div class=\\"line-num1\\"></div> <div class="line-num1"></div>
<div class=\\"line-num2\\">30</div> <div class="line-num2">30</div>
</td> </td>
<td class=\\"d2h-ins\\"> <td class="d2h-ins">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"> test</span> <span class="d2h-code-line-ctn"> test</span>
</div> </div>
</td> </td>
</tr>" </tr>"
@ -127,9 +167,19 @@ describe('LineByLineRenderer', () => {
}); });
it('should preserve tabs', () => { 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 hoganUtils = new HoganJsUtils({});
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {}); const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
const fileHtml = lineByLineRenderer.generateSingleLineHtml({ const fileHtml = lineByLineRenderer.generateSingleLineHtml(file, {
type: CSSLineClass.INSERTS, type: CSSLineClass.INSERTS,
prefix: '+', prefix: '+',
content: '\ttest', content: '\ttest',
@ -138,14 +188,14 @@ describe('LineByLineRenderer', () => {
}); });
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-code-linenumber d2h-ins\\"> <td class="d2h-code-linenumber d2h-ins">
<div class=\\"line-num1\\"></div> <div class="line-num1"></div>
<div class=\\"line-num2\\">30</div> <div class="line-num2">30</div>
</td> </td>
<td class=\\"d2h-ins\\"> <td class="d2h-ins">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"> test</span> <span class="d2h-code-line-ctn"> test</span>
</div> </div>
</td> </td>
</tr>" </tr>"
@ -173,22 +223,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs); const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-781444\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> "<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">my/file/name.js</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span> <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-file-diff\\"> <div class="d2h-file-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<span>Random Html</span> <span>Random Html</span>
</tbody> </tbody>
</table> </table>
@ -217,22 +267,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs); const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-781444\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> "<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">my/file/name.js</span>
<span class=\\"d2h-tag d2h-added d2h-added-tag\\">ADDED</span></span> <span class="d2h-tag d2h-added d2h-added-tag">ADDED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-file-diff\\"> <div class="d2h-file-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<span>Random Html</span> <span>Random Html</span>
</tbody> </tbody>
</table> </table>
@ -261,22 +311,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs); const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-781444\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> "<div id="d2h-781444" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">my/file/name.js</span>
<span class=\\"d2h-tag d2h-deleted d2h-deleted-tag\\">DELETED</span></span> <span class="d2h-tag d2h-deleted d2h-deleted-tag">DELETED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-file-diff\\"> <div class="d2h-file-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<span>Random Html</span> <span>Random Html</span>
</tbody> </tbody>
</table> </table>
@ -305,22 +355,22 @@ describe('LineByLineRenderer', () => {
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs); const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
"<div id=\\"d2h-662683\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> "<div id="d2h-662683" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </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> <span class="d2h-tag d2h-moved d2h-moved-tag">RENAMED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-file-diff\\"> <div class="d2h-file-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<span>Random Html</span> <span>Random Html</span>
</tbody> </tbody>
</table> </table>
@ -399,48 +449,48 @@ describe('LineByLineRenderer', () => {
}); });
const html = lineByLineRenderer.render(exampleJson); const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\"> "<div class="d2h-wrapper d2h-light-color-scheme">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"txt\\"> <div id="d2h-675094" class="d2h-file-wrapper" data-lang="txt">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span> <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-file-diff\\"> <div class="d2h-file-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-code-linenumber d2h-info\\"></td> <td class="d2h-code-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-line\\">@@ -1 +1 @@</div> <div class="d2h-code-line">@@ -1 +1 @@</div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\"> <td class="d2h-code-linenumber d2h-del d2h-change">
<div class=\\"line-num1\\">1</div> <div class="line-num1">1</div>
<div class=\\"line-num2\\"></div> <div class="line-num2"></div>
</td> </td>
<td class=\\"d2h-del d2h-change\\"> <td class="d2h-del d2h-change">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">-</span> <span class="d2h-code-line-prefix">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span> <span class="d2h-code-line-ctn"><del>test</del></span>
</div> </div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\"> <td class="d2h-code-linenumber d2h-ins d2h-change">
<div class=\\"line-num1\\"></div> <div class="line-num1"></div>
<div class=\\"line-num2\\">1</div> <div class="line-num2">1</div>
</td> </td>
<td class=\\"d2h-ins d2h-change\\"> <td class="d2h-ins d2h-change">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span> <span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div> </div>
</td> </td>
</tr> </tr>
@ -473,26 +523,26 @@ describe('LineByLineRenderer', () => {
}); });
const html = lineByLineRenderer.render(exampleJson); const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\"> "<div class="d2h-wrapper d2h-light-color-scheme">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span> <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-file-diff\\"> <div class="d2h-file-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
File without changes File without changes
</div> </div>
</td> </td>
@ -533,27 +583,27 @@ describe('LineByLineRenderer', () => {
const lineByLineRenderer = new LineByLineRenderer(hoganUtils); const lineByLineRenderer = new LineByLineRenderer(hoganUtils);
const html = lineByLineRenderer.render(exampleJson); const html = lineByLineRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\"> "<div class="d2h-wrapper d2h-light-color-scheme">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span> <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-file-diff\\"> <div class="d2h-file-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-code-linenumber d2h-info\\"></td> <td class="d2h-code-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-line\\"><a href=\\"http://example.com\\">Custom link to render</a></div> <div class="d2h-code-line"><a href="http://example.com">Custom link to render</a></div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -620,52 +670,52 @@ describe('LineByLineRenderer', () => {
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
"<tr> "<tr>
<td class=\\"d2h-code-linenumber d2h-info\\"></td> <td class="d2h-code-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-line\\">@@ -1 +1 @@</div> <div class="d2h-code-line">@@ -1 +1 @@</div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-linenumber d2h-cntx\\"> <td class="d2h-code-linenumber d2h-cntx">
<div class=\\"line-num1\\">1</div> <div class="line-num1">1</div>
<div class=\\"line-num2\\">1</div> <div class="line-num2">1</div>
</td> </td>
<td class=\\"d2h-cntx\\"> <td class="d2h-cntx">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span> <span class="d2h-code-line-prefix">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">one context line</span> <span class="d2h-code-line-ctn">one context line</span>
</div> </div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-linenumber d2h-del d2h-change\\"> <td class="d2h-code-linenumber d2h-del d2h-change">
<div class=\\"line-num1\\">2</div> <div class="line-num1">2</div>
<div class=\\"line-num2\\"></div> <div class="line-num2"></div>
</td> </td>
<td class=\\"d2h-del d2h-change\\"> <td class="d2h-del d2h-change">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">-</span> <span class="d2h-code-line-prefix">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span> <span class="d2h-code-line-ctn"><del>test</del></span>
</div> </div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-linenumber d2h-ins d2h-change\\"> <td class="d2h-code-linenumber d2h-ins d2h-change">
<div class=\\"line-num1\\"></div> <div class="line-num1"></div>
<div class=\\"line-num2\\">2</div> <div class="line-num2">2</div>
</td> </td>
<td class=\\"d2h-ins d2h-change\\"> <td class="d2h-ins d2h-change">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span> <span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div> </div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-linenumber d2h-ins\\"> <td class="d2h-code-linenumber d2h-ins">
<div class=\\"line-num1\\"></div> <div class="line-num1"></div>
<div class=\\"line-num2\\">3</div> <div class="line-num2">3</div>
</td> </td>
<td class=\\"d2h-ins\\"> <td class="d2h-ins">
<div class=\\"d2h-code-line\\"> <div class="d2h-code-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\">test2r</span> <span class="d2h-code-line-ctn">test2r</span>
</div> </div>
</td> </td>
</tr>" </tr>"

View file

@ -5,31 +5,31 @@ describe('Utils', () => {
describe('escapeForHtml', () => { describe('escapeForHtml', () => {
it('should escape & with &amp;', () => { it('should escape & with &amp;', () => {
const result = escapeForHtml('&'); const result = escapeForHtml('&');
expect(result).toEqual('&amp;'); expect(result).toBe('&amp;');
}); });
it('should escape < with &lt;', () => { it('should escape < with &lt;', () => {
const result = escapeForHtml('<'); const result = escapeForHtml('<');
expect(result).toEqual('&lt;'); expect(result).toBe('&lt;');
}); });
it('should escape > with &gt;', () => { it('should escape > with &gt;', () => {
const result = escapeForHtml('>'); const result = escapeForHtml('>');
expect(result).toEqual('&gt;'); expect(result).toBe('&gt;');
}); });
it('should escape " with &quot;', () => { it('should escape " with &quot;', () => {
const result = escapeForHtml('"'); const result = escapeForHtml('"');
expect(result).toEqual('&quot;'); expect(result).toBe('&quot;');
}); });
it("should escape ' with &#x27;", () => { it("should escape ' with &#x27;", () => {
const result = escapeForHtml("'"); const result = escapeForHtml("'");
expect(result).toEqual('&#x27;'); expect(result).toBe('&#x27;');
}); });
it('should escape / with &#x2F;', () => { it('should escape / with &#x2F;', () => {
const result = escapeForHtml('/'); const result = escapeForHtml('/');
expect(result).toEqual('&#x2F;'); expect(result).toBe('&#x2F;');
}); });
it('should escape a string containing HTML code', () => { it('should escape a string containing HTML code', () => {
const result = escapeForHtml(`<a href="/search?q=diff2html">Search 'Diff2Html'</a>`); 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;', '&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', oldName: 'sample.js',
newName: 'sample.js', newName: 'sample.js',
}); });
expect(result).toEqual('d2h-960013'); expect(result).toBe('d2h-960013');
}); });
}); });
@ -51,49 +51,49 @@ describe('Utils', () => {
oldName: 'sample.js', oldName: 'sample.js',
newName: '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', () => { it('should generate the file name for a changed file and full rename', () => {
const result = filenameDiff({ const result = filenameDiff({
oldName: 'sample1.js', oldName: 'sample1.js',
newName: 'sample2.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', () => { it('should generate the file name for a changed file and prefix rename', () => {
const result = filenameDiff({ const result = filenameDiff({
oldName: 'src/path/sample.js', oldName: 'src/path/sample.js',
newName: 'source/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', () => { it('should generate the file name for a changed file and suffix rename', () => {
const result = filenameDiff({ const result = filenameDiff({
oldName: 'src/path/sample1.js', oldName: 'src/path/sample1.js',
newName: 'src/path/sample2.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', () => { it('should generate the file name for a changed file and middle rename', () => {
const result = filenameDiff({ const result = filenameDiff({
oldName: 'src/really/big/path/sample.js', oldName: 'src/really/big/path/sample.js',
newName: 'src/small/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', () => { it('should generate the file name for a deleted file', () => {
const result = filenameDiff({ const result = filenameDiff({
oldName: 'src/my/file.js', oldName: 'src/my/file.js',
newName: '/dev/null', 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', () => { it('should generate the file name for a new file', () => {
const result = filenameDiff({ const result = filenameDiff({
oldName: '/dev/null', oldName: '/dev/null',
newName: 'src/my/file.js', 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 sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
const fileHtml = sideBySideRenderer.generateEmptyDiff(); const fileHtml = sideBySideRenderer.generateEmptyDiff();
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
Object { {
"left": "<tr> "left": "<tr>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
File without changes File without changes
</div> </div>
</td> </td>
@ -78,76 +78,76 @@ describe('SideBySideRenderer', () => {
const fileHtml = sideBySideRenderer.generateFileHtml(file); const fileHtml = sideBySideRenderer.generateFileHtml(file);
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
Object { {
"left": "<tr> "left": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td> <td class="d2h-code-side-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\">@@ -19,7 +19,7 @@</div> <div class="d2h-code-side-line">@@ -19,7 +19,7 @@</div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-cntx\\"> <td class="d2h-code-side-linenumber d2h-cntx">
19 19
</td> </td>
<td class=\\"d2h-cntx\\"> <td class="d2h-cntx">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span> <span class="d2h-code-line-prefix">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">context</span> <span class="d2h-code-line-ctn">context</span>
</div> </div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-del d2h-change\\"> <td class="d2h-code-side-linenumber d2h-del d2h-change">
20 20
</td> </td>
<td class=\\"d2h-del d2h-change\\"> <td class="d2h-del d2h-change">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">-</span> <span class="d2h-code-line-prefix">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>removed</del></span> <span class="d2h-code-line-ctn"><del>removed</del></span>
</div> </div>
</td> </td>
</tr><tr> </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>
<td class=\\"d2h-cntx d2h-emptyplaceholder\\"> <td class="d2h-cntx d2h-emptyplaceholder">
<div class=\\"d2h-code-side-line d2h-code-side-emptyplaceholder\\"> <div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span> <span class="d2h-code-line-prefix">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\"><br></span> <span class="d2h-code-line-ctn"><br></span>
</div> </div>
</td> </td>
</tr>", </tr>",
"right": "<tr> "right": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td> <td class="d2h-code-side-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\"></div> <div class="d2h-code-side-line">&nbsp;</div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-cntx\\"> <td class="d2h-code-side-linenumber d2h-cntx">
19 19
</td> </td>
<td class=\\"d2h-cntx\\"> <td class="d2h-cntx">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span> <span class="d2h-code-line-prefix">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\">context</span> <span class="d2h-code-line-ctn">context</span>
</div> </div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-ins d2h-change\\"> <td class="d2h-code-side-linenumber d2h-ins d2h-change">
20 20
</td> </td>
<td class=\\"d2h-ins d2h-change\\"> <td class="d2h-ins d2h-change">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>added</ins></span> <span class="d2h-code-line-ctn"><ins>added</ins></span>
</div> </div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-ins\\"> <td class="d2h-code-side-linenumber d2h-ins">
21 21
</td> </td>
<td class=\\"d2h-ins\\"> <td class="d2h-ins">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\">another added</span> <span class="d2h-code-line-ctn">another added</span>
</div> </div>
</td> </td>
</tr>", </tr>",
@ -168,26 +168,26 @@ describe('SideBySideRenderer', () => {
}); });
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
Object { {
"left": "<tr> "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>
<td class=\\"d2h-cntx d2h-emptyplaceholder\\"> <td class="d2h-cntx d2h-emptyplaceholder">
<div class=\\"d2h-code-side-line d2h-code-side-emptyplaceholder\\"> <div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span> <span class="d2h-code-line-prefix">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\"><br></span> <span class="d2h-code-line-ctn"><br></span>
</div> </div>
</td> </td>
</tr>", </tr>",
"right": "<tr> "right": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-ins\\"> <td class="d2h-code-side-linenumber d2h-ins">
30 30
</td> </td>
<td class=\\"d2h-ins\\"> <td class="d2h-ins">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\">test</span> <span class="d2h-code-line-ctn">test</span>
</div> </div>
</td> </td>
</tr>", </tr>",
@ -208,26 +208,26 @@ describe('SideBySideRenderer', () => {
); );
expect(fileHtml).toMatchInlineSnapshot(` expect(fileHtml).toMatchInlineSnapshot(`
Object { {
"left": "<tr> "left": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-del\\"> <td class="d2h-code-side-linenumber d2h-del">
30 30
</td> </td>
<td class=\\"d2h-del\\"> <td class="d2h-del">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">-</span> <span class="d2h-code-line-prefix">-</span>
<span class=\\"d2h-code-line-ctn\\">test</span> <span class="d2h-code-line-ctn">test</span>
</div> </div>
</td> </td>
</tr>", </tr>",
"right": "<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>
<td class=\\"d2h-cntx d2h-emptyplaceholder\\"> <td class="d2h-cntx d2h-emptyplaceholder">
<div class=\\"d2h-code-side-line d2h-code-side-emptyplaceholder\\"> <div class="d2h-code-side-line d2h-code-side-emptyplaceholder">
<span class=\\"d2h-code-line-prefix\\">&nbsp;</span> <span class="d2h-code-line-prefix">&nbsp;</span>
<span class=\\"d2h-code-line-ctn\\"><br></span> <span class="d2h-code-line-ctn"><br></span>
</div> </div>
</td> </td>
</tr>", </tr>",
@ -278,37 +278,37 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: LineMatchingType.LINES }); const sideBySideRenderer = new SideBySideRenderer(hoganUtils, { matching: LineMatchingType.LINES });
const html = sideBySideRenderer.render(exampleJson); const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\"> "<div class="d2h-wrapper d2h-light-color-scheme">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"txt\\"> <div id="d2h-675094" class="d2h-file-wrapper" data-lang="txt">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span> <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-files-diff\\"> <div class="d2h-files-diff">
<div class=\\"d2h-file-side-diff\\"> <div class="d2h-file-side-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td> <td class="d2h-code-side-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\">@@ -1 +1 @@</div> <div class="d2h-code-side-line">@@ -1 +1 @@</div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-del d2h-change\\"> <td class="d2h-code-side-linenumber d2h-del d2h-change">
1 1
</td> </td>
<td class=\\"d2h-del d2h-change\\"> <td class="d2h-del d2h-change">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">-</span> <span class="d2h-code-line-prefix">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span> <span class="d2h-code-line-ctn"><del>test</del></span>
</div> </div>
</td> </td>
</tr> </tr>
@ -316,23 +316,23 @@ describe('SideBySideRenderer', () => {
</table> </table>
</div> </div>
</div> </div>
<div class=\\"d2h-file-side-diff\\"> <div class="d2h-file-side-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td> <td class="d2h-code-side-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\"></div> <div class="d2h-code-side-line">&nbsp;</div>
</td> </td>
</tr><tr> </tr><tr>
<td class=\\"d2h-code-side-linenumber d2h-ins d2h-change\\"> <td class="d2h-code-side-linenumber d2h-ins d2h-change">
1 1
</td> </td>
<td class=\\"d2h-ins d2h-change\\"> <td class="d2h-ins d2h-change">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span> <span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div> </div>
</td> </td>
</tr> </tr>
@ -363,27 +363,27 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {}); const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
const html = sideBySideRenderer.render(exampleJson); const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\"> "<div class="d2h-wrapper d2h-light-color-scheme">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span> <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-files-diff\\"> <div class="d2h-files-diff">
<div class=\\"d2h-file-side-diff\\"> <div class="d2h-file-side-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
File without changes File without changes
</div> </div>
</td> </td>
@ -392,10 +392,10 @@ describe('SideBySideRenderer', () => {
</table> </table>
</div> </div>
</div> </div>
<div class=\\"d2h-file-side-diff\\"> <div class="d2h-file-side-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
</tbody> </tbody>
</table> </table>
@ -434,42 +434,42 @@ describe('SideBySideRenderer', () => {
const sideBySideRenderer = new SideBySideRenderer(hoganUtils); const sideBySideRenderer = new SideBySideRenderer(hoganUtils);
const html = sideBySideRenderer.render(exampleJson); const html = sideBySideRenderer.render(exampleJson);
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
"<div class=\\"d2h-wrapper\\"> "<div class="d2h-wrapper d2h-light-color-scheme">
<div id=\\"d2h-675094\\" class=\\"d2h-file-wrapper\\" data-lang=\\"js\\"> <div id="d2h-675094" class="d2h-file-wrapper" data-lang="js">
<div class=\\"d2h-file-header\\"> <div class="d2h-file-header">
<span class=\\"d2h-file-name-wrapper\\"> <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\\"> <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> <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> </svg> <span class="d2h-file-name">sample</span>
<span class=\\"d2h-tag d2h-changed d2h-changed-tag\\">CHANGED</span></span> <span class="d2h-tag d2h-changed d2h-changed-tag">CHANGED</span></span>
<label class=\\"d2h-file-collapse\\"> <label class="d2h-file-collapse">
<input class=\\"d2h-file-collapse-input\\" type=\\"checkbox\\" name=\\"viewed\\" value=\\"viewed\\"> <input class="d2h-file-collapse-input" type="checkbox" name="viewed" value="viewed">
Viewed Viewed
</label> </label>
</div> </div>
<div class=\\"d2h-files-diff\\"> <div class="d2h-files-diff">
<div class=\\"d2h-file-side-diff\\"> <div class="d2h-file-side-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td> <td class="d2h-code-side-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\"><a href=\\"http://example.com\\">Custom link to render</a></div> <div class="d2h-code-side-line"><a href="http://example.com">Custom link to render</a></div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
</table> </table>
</div> </div>
</div> </div>
<div class=\\"d2h-file-side-diff\\"> <div class="d2h-file-side-diff">
<div class=\\"d2h-code-wrapper\\"> <div class="d2h-code-wrapper">
<table class=\\"d2h-diff-table\\"> <table class="d2h-diff-table">
<tbody class=\\"d2h-diff-tbody\\"> <tbody class="d2h-diff-tbody">
<tr> <tr>
<td class=\\"d2h-code-side-linenumber d2h-info\\"></td> <td class="d2h-code-side-linenumber d2h-info"></td>
<td class=\\"d2h-info\\"> <td class="d2h-info">
<div class=\\"d2h-code-side-line\\"></div> <div class="d2h-code-side-line">&nbsp;</div>
</td> </td>
</tr> </tr>
</tbody> </tbody>
@ -508,26 +508,26 @@ describe('SideBySideRenderer', () => {
const html = sideBySideRenderer.processChangedLines(false, oldLines, newLines); const html = sideBySideRenderer.processChangedLines(false, oldLines, newLines);
expect(html).toMatchInlineSnapshot(` expect(html).toMatchInlineSnapshot(`
Object { {
"left": "<tr> "left": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-del d2h-change\\"> <td class="d2h-code-side-linenumber d2h-del d2h-change">
1 1
</td> </td>
<td class=\\"d2h-del d2h-change\\"> <td class="d2h-del d2h-change">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">-</span> <span class="d2h-code-line-prefix">-</span>
<span class=\\"d2h-code-line-ctn\\"><del>test</del></span> <span class="d2h-code-line-ctn"><del>test</del></span>
</div> </div>
</td> </td>
</tr>", </tr>",
"right": "<tr> "right": "<tr>
<td class=\\"d2h-code-side-linenumber d2h-ins d2h-change\\"> <td class="d2h-code-side-linenumber d2h-ins d2h-change">
1 1
</td> </td>
<td class=\\"d2h-ins d2h-change\\"> <td class="d2h-ins d2h-change">
<div class=\\"d2h-code-side-line\\"> <div class="d2h-code-side-line">
<span class=\\"d2h-code-line-prefix\\">+</span> <span class="d2h-code-line-prefix">+</span>
<span class=\\"d2h-code-line-ctn\\"><ins>test1r</ins></span> <span class="d2h-code-line-ctn"><ins>test1r</ins></span>
</div> </div>
</td> </td>
</tr>", </tr>",

View file

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

View file

@ -272,7 +272,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
const nxtLine = diffLines[lineIndex + 1]; const nxtLine = diffLines[lineIndex + 1];
const afterNxtLine = diffLines[lineIndex + 2]; const afterNxtLine = diffLines[lineIndex + 2];
if (line.startsWith('diff')) { if (line.startsWith('diff --git') || line.startsWith('diff --combined')) {
startFile(); startFile();
// diff --git a/blocked_delta_results.png b/blocked_delta_results.png // diff --git a/blocked_delta_results.png b/blocked_delta_results.png
@ -290,6 +290,22 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
return; 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 ( if (
!currentFile || // If we do not have a file yet, we should crete one !currentFile || // If we do not have a file yet, we should crete one
(!currentFile.isGitDiff && (!currentFile.isGitDiff &&
@ -442,18 +458,16 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
} else if ((values = index.exec(line))) { } else if ((values = index.exec(line))) {
currentFile.checksumBefore = values[1]; currentFile.checksumBefore = values[1];
currentFile.checksumAfter = values[2]; currentFile.checksumAfter = values[2];
values[3] && (currentFile.mode = values[3]); if (values[3]) currentFile.mode = values[3];
} else if ((values = combinedIndex.exec(line))) { } else if ((values = combinedIndex.exec(line))) {
currentFile.checksumBefore = [values[2], values[3]]; currentFile.checksumBefore = [values[2], values[3]];
currentFile.checksumAfter = values[1]; currentFile.checksumAfter = values[1];
} else if ((values = combinedMode.exec(line))) { } else if ((values = combinedMode.exec(line))) {
currentFile.oldMode = [values[2], values[3]]; currentFile.oldMode = [values[2], values[3]];
currentFile.newMode = values[1]; currentFile.newMode = values[1];
// eslint-disable-next-line sonarjs/no-duplicated-branches
} else if ((values = combinedNewFile.exec(line))) { } else if ((values = combinedNewFile.exec(line))) {
currentFile.newFileMode = values[1]; currentFile.newFileMode = values[1];
currentFile.isNew = true; currentFile.isNew = true;
// eslint-disable-next-line sonarjs/no-duplicated-branches
} else if ((values = combinedDeletedFile.exec(line))) { } else if ((values = combinedDeletedFile.exec(line))) {
currentFile.deletedFileMode = values[1]; currentFile.deletedFileMode = values[1];
currentFile.isDeleted = true; currentFile.isDeleted = true;

View file

@ -1,5 +1,5 @@
import * as DiffParser from './diff-parser'; 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 LineByLineRenderer, { LineByLineRendererConfig, defaultLineByLineRendererConfig } from './line-by-line-renderer';
import SideBySideRenderer, { SideBySideRendererConfig, defaultSideBySideRendererConfig } from './side-by-side-renderer'; import SideBySideRenderer, { SideBySideRendererConfig, defaultSideBySideRendererConfig } from './side-by-side-renderer';
import { DiffFile, OutputFormatType } from './types'; import { DiffFile, OutputFormatType } from './types';
@ -32,7 +32,10 @@ export function html(diffInput: string | DiffFile[], configuration: Diff2HtmlCon
const hoganUtils = new HoganJsUtils(config); 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 = const diffOutput =
config.outputFormat === 'side-by-side' config.outputFormat === 'side-by-side'

View file

@ -1,33 +1,52 @@
import * as renderUtils from './render-utils'; import * as renderUtils from './render-utils';
import HoganJsUtils from './hoganjs-utils'; import HoganJsUtils from './hoganjs-utils';
import { DiffFile } from './types'; import { ColorSchemeType, DiffFile } from './types';
const baseTemplatesPath = 'file-summary'; const baseTemplatesPath = 'file-summary';
const iconsBaseTemplatesPath = 'icon'; const iconsBaseTemplatesPath = 'icon';
export function render(diffFiles: DiffFile[], hoganUtils: HoganJsUtils): string { export interface FileListRendererConfig {
const files = diffFiles colorScheme?: ColorSchemeType;
.map(file => }
hoganUtils.render(
baseTemplatesPath, export const defaultFileListRendererConfig = {
'line', colorScheme: renderUtils.defaultRenderConfig.colorScheme,
{ };
fileHtmlId: renderUtils.getHtmlId(file),
oldName: file.oldName, export class FileListRenderer {
newName: file.newName, private readonly hoganUtils: HoganJsUtils;
fileName: renderUtils.filenameDiff(file), private readonly config: typeof defaultFileListRendererConfig;
deletedLines: '-' + file.deletedLines,
addedLines: '+' + file.addedLines, constructor(hoganUtils: HoganJsUtils, config: FileListRendererConfig = {}) {
}, this.hoganUtils = hoganUtils;
{ this.config = { ...defaultFileListRendererConfig, ...config };
fileIcon: hoganUtils.template(iconsBaseTemplatesPath, renderUtils.getFileIcon(file)), }
},
), render(diffFiles: DiffFile[]): string {
) const files = diffFiles
.join('\n'); .map(file =>
this.hoganUtils.render(
return hoganUtils.render(baseTemplatesPath, 'wrapper', { baseTemplatesPath,
filesNumber: diffFiles.length, 'line',
files: files, {
}); 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 { try {
const template = this.preCompiledTemplates[templateKey]; const template = this.preCompiledTemplates[templateKey];
return template.render(params, partials, indent); return template.render(params, partials, indent);
} catch (e) { } catch (_e) {
throw new Error(`Could not find template to render '${templateKey}'`); throw new Error(`Could not find template to render '${templateKey}'`);
} }
} }

View file

@ -52,7 +52,10 @@ export default class LineByLineRenderer {
}) })
.join('\n'); .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 { makeFileDiffHtml(file: DiffFile, diffs: string): string {
@ -103,14 +106,14 @@ export default class LineByLineRenderer {
this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => { this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => {
if (oldLines.length && newLines.length && !contextLines.length) { if (oldLines.length && newLines.length && !contextLines.length) {
this.applyRematchMatching(oldLines, newLines, matcher).map(([oldLines, newLines]) => { 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 += left;
lines += right; lines += right;
}); });
} else if (contextLines.length) { } else if (contextLines.length) {
contextLines.forEach(line => { contextLines.forEach(line => {
const { prefix, content } = renderUtils.deconstructLine(line.content, file.isCombined); const { prefix, content } = renderUtils.deconstructLine(line.content, file.isCombined);
lines += this.generateSingleLineHtml({ lines += this.generateSingleLineHtml(file, {
type: renderUtils.CSSLineClass.CONTEXT, type: renderUtils.CSSLineClass.CONTEXT,
prefix: prefix, prefix: prefix,
content: content, content: content,
@ -119,7 +122,7 @@ export default class LineByLineRenderer {
}); });
}); });
} else if (oldLines.length || newLines.length) { } 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 += left;
lines += right; lines += right;
} else { } else {
@ -188,7 +191,7 @@ export default class LineByLineRenderer {
return doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]]; 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 = { const fileHtml = {
right: '', right: '',
left: '', left: '',
@ -240,7 +243,7 @@ export default class LineByLineRenderer {
} }
: undefined; : undefined;
const { left, right } = this.generateLineHtml(preparedOldLine, preparedNewLine); const { left, right } = this.generateLineHtml(file, preparedOldLine, preparedNewLine);
fileHtml.left += left; fileHtml.left += left;
fileHtml.right += right; fileHtml.right += right;
} }
@ -248,14 +251,14 @@ export default class LineByLineRenderer {
return fileHtml; return fileHtml;
} }
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml { generateLineHtml(file: DiffFile, oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
return { return {
left: this.generateSingleLineHtml(oldLine), left: this.generateSingleLineHtml(file, oldLine),
right: this.generateSingleLineHtml(newLine), right: this.generateSingleLineHtml(file, newLine),
}; };
} }
generateSingleLineHtml(line?: DiffPreparedLine): string { generateSingleLineHtml(file: DiffFile, line?: DiffPreparedLine): string {
if (line === undefined) return ''; if (line === undefined) return '';
const lineNumberHtml = this.hoganUtils.render(baseTemplatesPath, 'numbers', { const lineNumberHtml = this.hoganUtils.render(baseTemplatesPath, 'numbers', {
@ -270,6 +273,8 @@ export default class LineByLineRenderer {
prefix: line.prefix === ' ' ? '&nbsp;' : line.prefix, prefix: line.prefix === ' ' ? '&nbsp;' : line.prefix,
content: line.content, content: line.content,
lineNumber: lineNumberHtml, lineNumber: lineNumberHtml,
line,
file,
}); });
} }
} }

View file

@ -2,7 +2,15 @@ import * as jsDiff from 'diff';
import { unifyPath, hashCode } from './utils'; import { unifyPath, hashCode } from './utils';
import * as rematch from './rematch'; 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 = export type CSSLineClass =
| 'd2h-ins' | 'd2h-ins'
@ -37,6 +45,7 @@ export interface RenderConfig {
matchWordsThreshold?: number; matchWordsThreshold?: number;
maxLineLengthHighlight?: number; maxLineLengthHighlight?: number;
diffStyle?: DiffStyleType; diffStyle?: DiffStyleType;
colorScheme?: ColorSchemeType;
} }
export const defaultRenderConfig = { export const defaultRenderConfig = {
@ -44,6 +53,7 @@ export const defaultRenderConfig = {
matchWordsThreshold: 0.25, matchWordsThreshold: 0.25,
maxLineLengthHighlight: 10000, maxLineLengthHighlight: 10000,
diffStyle: DiffStyleType.WORD, diffStyle: DiffStyleType.WORD,
colorScheme: ColorSchemeType.LIGHT,
}; };
const separator = '/'; 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 * Prefix length of the hunk lines in the diff
*/ */

View file

@ -52,7 +52,10 @@ export default class SideBySideRenderer {
}) })
.join('\n'); .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 { makeFileDiffHtml(file: DiffFile, diffs: FileHtml): string {

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"> <div class="d2h-file-list-header">
<span class="d2h-file-list-title">Files changed ({{filesNumber}})</span> <span class="d2h-file-list-title">Files changed ({{filesNumber}})</span>
<a class="d2h-file-switch d2h-hide">hide</a> <a class="d2h-file-switch d2h-hide">hide</a>

View file

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

View file

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

View file

@ -91,3 +91,9 @@ export const DiffStyleType: { [_: string]: DiffStyleType } = {
WORD: 'word', WORD: 'word',
CHAR: 'char', CHAR: 'char',
}; };
export enum ColorSchemeType {
AUTO = 'auto',
DARK = 'dark',
LIGHT = 'light',
}

View file

@ -5,8 +5,80 @@
* *
*/ */
.d2h-d-none { :root,
display: none; :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 { .d2h-wrapper {
@ -17,11 +89,17 @@
display: flex; display: flex;
height: 35px; height: 35px;
padding: 5px 10px; padding: 5px 10px;
border-bottom: 1px solid #d8d8d8; border-bottom: 1px solid var(--d2h-file-header-border-color);
background-color: #f7f7f7; background-color: var(--d2h-file-header-bg-color);
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif; 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 { .d2h-file-stats {
display: -webkit-box; display: -webkit-box;
display: -ms-flexbox; display: -ms-flexbox;
@ -32,18 +110,18 @@
.d2h-lines-added { .d2h-lines-added {
text-align: right; text-align: right;
border: 1px solid #b4e2b4; border: 1px solid var(--d2h-ins-border-color);
border-radius: 5px 0 0 5px; border-radius: 5px 0 0 5px;
color: #399839; color: var(--d2h-ins-label-color);
padding: 2px; padding: 2px;
vertical-align: middle; vertical-align: middle;
} }
.d2h-lines-deleted { .d2h-lines-deleted {
text-align: left; text-align: left;
border: 1px solid #e9aeae; border: 1px solid var(--d2h-del-border-color);
border-radius: 0 5px 5px 0; border-radius: 0 5px 5px 0;
color: #c33; color: var(--d2h-del-label-color);
padding: 2px; padding: 2px;
vertical-align: middle; vertical-align: middle;
margin-left: 1px; margin-left: 1px;
@ -67,7 +145,7 @@
} }
.d2h-file-wrapper { .d2h-file-wrapper {
border: 1px solid #ddd; border: 1px solid var(--d2h-border-color);
border-radius: 3px; border-radius: 3px;
margin-bottom: 1em; margin-bottom: 1em;
} }
@ -79,12 +157,12 @@
font-size: 12px; font-size: 12px;
align-items: center; align-items: center;
border-radius: 3px; border-radius: 3px;
border: 1px solid #ddd; border: 1px solid var(--d2h-border-color);
padding: 4px 8px; padding: 4px 8px;
} }
.d2h-file-collapse.d2h-selected { .d2h-file-collapse.d2h-selected {
background-color: #c8e1ff; background-color: var(--d2h-selected-color);
} }
.d2h-file-collapse-input { .d2h-file-collapse-input {
@ -99,7 +177,7 @@
} }
.d2h-files-diff { .d2h-files-diff {
display: block; display: flex;
width: 100%; width: 100%;
} }
@ -107,20 +185,23 @@
overflow-y: hidden; overflow-y: hidden;
} }
.d2h-files-diff.d2h-d-none,
.d2h-file-diff.d2h-d-none {
display: none;
}
.d2h-file-side-diff { .d2h-file-side-diff {
display: inline-block; display: inline-block;
overflow-x: scroll; overflow-x: scroll;
overflow-y: hidden; overflow-y: hidden;
width: 50%; width: 50%;
margin-right: -4px;
margin-bottom: -8px;
} }
.d2h-code-line { .d2h-code-line {
display: inline-block; display: inline-block;
white-space: nowrap; white-space: nowrap;
user-select: none; user-select: none;
width: 100%; width: calc(100% - 16em);
/* Compensate for the absolute positioning of the line numbers */ /* Compensate for the absolute positioning of the line numbers */
padding: 0 8em; padding: 0 8em;
} }
@ -129,7 +210,7 @@
display: inline-block; display: inline-block;
white-space: nowrap; white-space: nowrap;
user-select: none; user-select: none;
width: 100%; width: calc(100% - 9em);
/* Compensate for the absolute positioning of the line numbers */ /* Compensate for the absolute positioning of the line numbers */
padding: 0 4.5em; padding: 0 4.5em;
} }
@ -150,9 +231,8 @@
display: inline-block; display: inline-block;
margin-top: -1px; margin-top: -1px;
text-decoration: none; text-decoration: none;
background-color: #ffb6ba; background-color: var(--d2h-del-highlight-bg-color);
border-radius: 0.2em; border-radius: 0.2em;
vertical-align: middle;
} }
.d2h-code-line ins, .d2h-code-line ins,
@ -160,10 +240,9 @@
display: inline-block; display: inline-block;
margin-top: -1px; margin-top: -1px;
text-decoration: none; text-decoration: none;
background-color: #97f295; background-color: var(--d2h-ins-highlight-bg-color);
border-radius: 0.2em; border-radius: 0.2em;
text-align: left; text-align: left;
vertical-align: middle;
} }
.d2h-code-line-prefix { .d2h-code-line-prefix {
@ -198,10 +277,10 @@
/* Keep the numbers fixed on line contents scroll */ /* Keep the numbers fixed on line contents scroll */
position: absolute; position: absolute;
display: inline-block; display: inline-block;
background-color: #fff; background-color: var(--d2h-bg-color);
color: rgba(0, 0, 0, 0.3); color: var(--d2h-dim-color);
text-align: right; text-align: right;
border: solid #eeeeee; border: solid var(--d2h-line-border-color);
border-width: 0 1px 0 1px; border-width: 0 1px 0 1px;
cursor: pointer; cursor: pointer;
} }
@ -216,10 +295,10 @@
display: inline-block; display: inline-block;
box-sizing: border-box; box-sizing: border-box;
width: 4em; width: 4em;
background-color: #fff; background-color: var(--d2h-bg-color);
color: rgba(0, 0, 0, 0.3); color: var(--d2h-dim-color);
text-align: right; text-align: right;
border: solid #eeeeee; border: solid var(--d2h-line-border-color);
border-width: 0 1px 0 1px; border-width: 0 1px 0 1px;
cursor: pointer; cursor: pointer;
overflow: hidden; overflow: hidden;
@ -233,8 +312,8 @@
.d2h-code-side-emptyplaceholder, .d2h-code-side-emptyplaceholder,
.d2h-emptyplaceholder { .d2h-emptyplaceholder {
background-color: #f1f1f1; background-color: var(--d2h-empty-placeholder-bg-color);
border-color: #e1e1e1; border-color: var(--d2h-empty-placeholder-border-color);
} }
.d2h-code-linenumber, .d2h-code-linenumber,
@ -254,27 +333,27 @@
*/ */
.d2h-del { .d2h-del {
background-color: #fee8e9; background-color: var(--d2h-del-bg-color);
border-color: #e9aeae; border-color: var(--d2h-del-border-color);
} }
.d2h-ins { .d2h-ins {
background-color: #dfd; background-color: var(--d2h-ins-bg-color);
border-color: #b4e2b4; border-color: var(--d2h-ins-border-color);
} }
.d2h-info { .d2h-info {
background-color: #f8fafd; background-color: var(--d2h-info-bg-color);
color: rgba(0, 0, 0, 0.3); color: var(--d2h-dim-color);
border-color: #d5e4f2; border-color: var(--d2h-info-border-color);
} }
.d2h-file-diff .d2h-del.d2h-change { .d2h-file-diff .d2h-del.d2h-change {
background-color: #fdf2d0; background-color: var(--d2h-change-del-color);
} }
.d2h-file-diff .d2h-ins.d2h-change { .d2h-file-diff .d2h-ins.d2h-change {
background-color: #ded; background-color: var(--d2h-change-ins-color);
} }
/* /*
@ -287,11 +366,11 @@
.d2h-file-list-wrapper a { .d2h-file-list-wrapper a {
text-decoration: none; text-decoration: none;
color: #3572b0; color: var(--d2h-moved-label-color);
} }
.d2h-file-list-wrapper a:visited { .d2h-file-list-wrapper a:visited {
color: #3572b0; color: var(--d2h-moved-label-color);
} }
.d2h-file-list-header { .d2h-file-list-header {
@ -317,7 +396,7 @@
} }
.d2h-file-list > li { .d2h-file-list > li {
border-bottom: #ddd solid 1px; border-bottom: var(--d2h-border-color) solid 1px;
padding: 5px 10px; padding: 5px 10px;
margin: 0; margin: 0;
} }
@ -339,19 +418,19 @@
} }
.d2h-deleted { .d2h-deleted {
color: #c33; color: var(--d2h-del-label-color);
} }
.d2h-added { .d2h-added {
color: #399839; color: var(--d2h-ins-label-color);
} }
.d2h-changed { .d2h-changed {
color: #d0b44c; color: var(--d2h-change-label-color);
} }
.d2h-moved { .d2h-moved {
color: #3572b0; color: var(--d2h-moved-label-color);
} }
.d2h-tag { .d2h-tag {
@ -361,21 +440,302 @@
font-size: 10px; font-size: 10px;
margin-left: 5px; margin-left: 5px;
padding: 0 2px; padding: 0 2px;
background-color: #fff; background-color: var(--d2h-bg-color);
} }
.d2h-deleted-tag { .d2h-deleted-tag {
border: #c33 1px solid; border: var(--d2h-del-label-color) 1px solid;
} }
.d2h-added-tag { .d2h-added-tag {
border: #399839 1px solid; border: var(--d2h-ins-label-color) 1px solid;
} }
.d2h-changed-tag { .d2h-changed-tag {
border: #d0b44c 1px solid; border: var(--d2h-change-label-color) 1px solid;
} }
.d2h-moved-tag { .d2h-moved-tag {
border: #3572b0 1px solid; border: var(--d2h-moved-label-color) 1px solid;
}
/**
* Dark Mode Colors
*/
.d2h-dark-color-scheme {
color: var(--d2h-dark-color);
background-color: var(--d2h-dark-bg-color);
}
.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);
}
.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,4 +1,4 @@
import { closeTags, nodeStream, mergeStreams } from './highlight.js-helpers'; import { closeTags, nodeStream, mergeStreams, getLanguage } from './highlight.js-helpers';
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from '../../diff2html'; import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from '../../diff2html';
import { DiffFile } from '../../types'; import { DiffFile } from '../../types';
@ -9,12 +9,14 @@ export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
highlight?: boolean; highlight?: boolean;
fileListToggle?: boolean; fileListToggle?: boolean;
fileListStartVisible?: boolean; fileListStartVisible?: boolean;
highlightLanguages?: Map<string, string>;
/** /**
* @deprecated since version 3.1.0 * @deprecated since version 3.1.0
* Smart selection is now enabled by default with vanilla CSS * Smart selection is now enabled by default with vanilla CSS
*/ */
smartSelection?: boolean; smartSelection?: boolean;
fileContentToggle?: boolean; fileContentToggle?: boolean;
stickyFileHeaders?: boolean;
} }
export const defaultDiff2HtmlUIConfig = { export const defaultDiff2HtmlUIConfig = {
@ -23,12 +25,14 @@ export const defaultDiff2HtmlUIConfig = {
highlight: true, highlight: true,
fileListToggle: true, fileListToggle: true,
fileListStartVisible: false, fileListStartVisible: false,
highlightLanguages: new Map<string, string>(),
/** /**
* @deprecated since version 3.1.0 * @deprecated since version 3.1.0
* Smart selection is now enabled by default with vanilla CSS * Smart selection is now enabled by default with vanilla CSS
*/ */
smartSelection: true, smartSelection: true,
fileContentToggle: true, fileContentToggle: true,
stickyFileHeaders: true,
}; };
export class Diff2HtmlUI { export class Diff2HtmlUI {
@ -52,6 +56,7 @@ export class Diff2HtmlUI {
if (this.config.highlight) this.highlightCode(); if (this.config.highlight) this.highlightCode();
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible); if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
if (this.config.fileContentToggle) this.fileContentToggle(); if (this.config.fileContentToggle) this.fileContentToggle();
if (this.config.stickyFileHeaders) this.stickyFileHeaders();
} }
synchronisedScroll(): void { synchronisedScroll(): void {
@ -132,32 +137,43 @@ export class Diff2HtmlUI {
} }
highlightCode(): void { 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.'); 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 // Collect all the diff files and execute the highlight on their lines
const files = this.targetElement.querySelectorAll('.d2h-file-wrapper'); const files = this.targetElement.querySelectorAll('.d2h-file-wrapper');
files.forEach(file => { files.forEach(file => {
// HACK: help Typescript know that `this.hljs` is defined since we already checked it
if (this.hljs === null) return;
const language = file.getAttribute('data-lang'); const language = file.getAttribute('data-lang');
const hljsLanguage = language ? this.hljs.getLanguage(language) : undefined;
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 // Collect all the code lines and execute the highlight on them
const codeLines = file.querySelectorAll('.d2h-code-line-ctn'); const codeLines = file.querySelectorAll('.d2h-code-line-ctn');
codeLines.forEach(line => { 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 text = line.textContent;
const lineParent = line.parentNode; const lineParent = line.parentNode;
if (text === null || lineParent === null || !this.isElement(lineParent)) return; if (text === null || lineParent === null || !this.isElement(lineParent)) return;
const result: HighlightResult = closeTags( const result: HighlightResult = closeTags(
this.hljs.highlight(text, { hljs.highlight(text, {
language: hljsLanguage?.name || 'plaintext', language: hljsLanguage,
ignoreIllegals: true, ignoreIllegals: true,
}), }),
); );
@ -178,6 +194,12 @@ export class Diff2HtmlUI {
}); });
} }
stickyFileHeaders(): void {
this.targetElement.querySelectorAll('.d2h-file-header').forEach(header => {
header.classList.add('d2h-sticky-header');
});
}
/** /**
* @deprecated since version 3.1.0 * @deprecated since version 3.1.0
*/ */

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

@ -158,3 +158,498 @@ export function closeTags(res: HighlightResult): HighlightResult {
return res; 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';
}

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": { "compilerOptions": {
"outDir": "./_target", "outDir": "bundles-out",
"target": "es5", "module": "CommonJS",
"module": "commonjs", "moduleResolution": "Node",
"moduleResolution": "node", "target": "ES6",
"lib": ["es2020", "dom"], "lib": ["ES6", "DOM"],
"jsx": "preserve",
"allowJs": false, "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, "declaration": true,
"declarationMap": true, "declarationMap": true,
"sourceMap": true,
"noEmit": false,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"incremental": false,
"strictNullChecks": true, "strictNullChecks": true,
"removeComments": true, "removeComments": true,
"preserveConstEnums": true, "preserveConstEnums": true,
"sourceMap": true,
"alwaysStrict": true, "alwaysStrict": true,
"strict": true,
"noImplicitAny": true, "noImplicitAny": true,
"noImplicitThis": true, "noImplicitThis": true
"noUnusedParameters": true, }
"noUnusedLocals": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"forceConsistentCasingInFileNames": true,
"esModuleInterop": true
},
"include": ["./src/**/*", "./typings/**/*"],
"exclude": ["node_modules", "./src/__tests__/*"]
} }

1
typings/merge.d.ts vendored
View file

@ -1,4 +1,3 @@
declare module 'merge' { declare module 'merge' {
// eslint-disable-next-line @typescript-eslint/ban-types
export function recursive(clone: boolean, ...items: object[]): object; export function recursive(clone: boolean, ...items: object[]): object;
} }

View file

@ -3,7 +3,7 @@ import path from 'path';
import webpack from 'webpack'; import webpack from 'webpack';
import HtmlWebpackPlugin from 'html-webpack-plugin'; import HtmlWebpackPlugin from 'html-webpack-plugin';
import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import MiniCssExtractPlugin from 'mini-css-extract-plugin';
import CopyWebpackPlugin from 'copy-webpack-plugin'; import CopyPlugin from 'copy-webpack-plugin';
const pages = ['index', 'demo']; const pages = ['index', 'demo'];
@ -37,7 +37,7 @@ function plugins(page: string): Plugin[] {
minifyURLs: true, minifyURLs: true,
}, },
}), }),
new CopyWebpackPlugin({ new CopyPlugin({
patterns: [ patterns: [
{ from: 'website/favicon.ico', to: 'favicon.ico' }, { from: 'website/favicon.ico', to: 'favicon.ico' },
{ from: 'website/robots.txt', to: 'robots.txt' }, { from: 'website/robots.txt', to: 'robots.txt' },

View file

@ -2,7 +2,7 @@
<div class="hero-body"> <div class="hero-body">
<div class="container"> <div class="container">
<h1 class="title is-size-1 is-spaced">Demo<a href="#help"> <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"> aria-hidden="true">
<path <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"> 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>
<div class="columns is-desktop is-multiline"> <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"> <label title="Output format of the HTML, either line by line or side by side">
<p>Output Format</p> <p>Output Format</p>
<select class="options-label-value" id="diff-url-options-output-format" name="outputFormat"> <select class="options-label-value" id="diff-url-options-output-format" name="outputFormat">
@ -42,14 +42,24 @@
</select> </select>
</label> </label>
</div> </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"> <label title="Show the file list summary before the diff">
<p>File Summary</p> <p>File Summary</p>
<input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="drawFileList" <input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="drawFileList"
checked /> checked />
</label> </label>
</div> </div>
<div class="column is-one-fifth-widescreen"> <div class="column is-one-sixth-widescreen">
<label title="Level of matching for the comparison algorithm"> <label title="Level of matching for the comparison algorithm">
<p>Matching Type</p> <p>Matching Type</p>
<select class="options-label-value" id="diff-url-options-matching" name="matching"> <select class="options-label-value" id="diff-url-options-matching" name="matching">
@ -59,14 +69,14 @@
</select> </select>
</label> </label>
</div> </div>
<div class="column is-one-fifth-widescreen"> <div class="column is-one-sixth-widescreen">
<label title="Similarity threshold for the matching algorithm"> <label title="Similarity threshold for the matching algorithm">
<p>Words Threshold</p> <p>Words Threshold</p>
<input class="options-label-value" id="diff-url-options-match-words-threshold" type="number" <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" /> name="matchWordsThreshold" value="0.25" step="0.05" min="0" max="1" />
</label> </label>
</div> </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"> <label title="Maximum number of comparison performed by the matching algorithm in a block of changes">
<p>Max Comparisons</p> <p>Max Comparisons</p>
<input class="options-label-value" id="diff-url-options-matching-max-comparisons" type="number" <input class="options-label-value" id="diff-url-options-matching-max-comparisons" type="number"
@ -134,4 +144,4 @@
providing better diff support for existing online services. providing better diff support for existing online services.
</p> </p>
</div> </div>
</section> </section>

View file

@ -5,3 +5,21 @@
.diff-url-btn.is-small { .diff-url-btn.is-small {
font-size: 0.85rem; 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.ts';
import '../../../main.css'; import '../../../main.css';
import 'highlight.js/styles/github.css'; import './github-highlights.css';
import '../../../../src/ui/css/diff2html.css'; import '../../../../src/ui/css/diff2html.css';
import './demo.css'; import './demo.css';
import { colorSchemeToCss } from '../../../../src/render-utils';
import { ColorSchemeType } from '../../../../src/types';
/* /*
* Example URLs: * Example URLs:
@ -22,7 +24,7 @@ import './demo.css';
type URLParams = { type URLParams = {
diff?: string; diff?: string;
diffTooBigMessage?: string; diffTooBigMessage?: string;
[key: string]: string | boolean | number | undefined; [key: string]: string | boolean | number | Map<string, string> | undefined;
}; };
const searchParam = 'diff'; const searchParam = 'diff';
@ -121,10 +123,16 @@ function prepareRequest(url: string): Request {
function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig { function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
// Removing `diff` and `diffTooBigMessage` form `urlParams` to avoid being inserted // Removing `diff` and `diffTooBigMessage` form `urlParams` to avoid being inserted
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const { diff, diffTooBigMessage, ...urlParamsRest } = urlParams; const { diff, diffTooBigMessage, ...urlParamsRest } = urlParams;
const defaultColorScheme: ColorSchemeType =
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? ColorSchemeType.DARK
: ColorSchemeType.LIGHT;
const config: URLParams = { const config: URLParams = {
...defaultDiff2HtmlUIConfig, ...defaultDiff2HtmlUIConfig,
colorScheme: defaultColorScheme,
...urlParamsRest, ...urlParamsRest,
}; };
@ -132,8 +140,8 @@ function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
const newObject = !Number.isNaN(Number(v)) const newObject = !Number.isNaN(Number(v))
? { [k]: Number(v) } ? { [k]: Number(v) }
: v === 'true' || v === 'false' : v === 'true' || v === 'false'
? { [k]: Boolean(v) } ? { [k]: Boolean(v) }
: { [k]: v }; : { [k]: v };
return { ...object, ...newObject }; return { ...object, ...newObject };
}, {}); }, {});
} }
@ -155,9 +163,16 @@ async function getDiff(request: Request): Promise<string> {
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void { function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
const diff2htmlUi = new Diff2HtmlUI(elements.structure.diffTarget, diffString, config); const diff2htmlUi = new Diff2HtmlUI(elements.structure.diffTarget, diffString, config);
setBodyColorScheme(diff2htmlUi.config.colorScheme);
diff2htmlUi.draw(); diff2htmlUi.draw();
} }
function setBodyColorScheme(colorScheme: ColorSchemeType): void {
document.body.className = colorSchemeToCss(colorScheme);
}
async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConfig, string]> { async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConfig, string]> {
const urlParams = getParamsFromSearch(window.location.search); const urlParams = getParamsFromSearch(window.location.search);
const currentUrl = (urlParams && urlParams[searchParam]) || 'https://github.com/rtfpessoa/diff2html/pull/106'; const currentUrl = (urlParams && urlParams[searchParam]) || 'https://github.com/rtfpessoa/diff2html/pull/106';
@ -200,6 +215,7 @@ type Elements = {
}; };
options: { options: {
outputFormat: HTMLInputElement; outputFormat: HTMLInputElement;
colorScheme: HTMLInputElement;
matching: HTMLInputElement; matching: HTMLInputElement;
wordsThreshold: HTMLInputElement; wordsThreshold: HTMLInputElement;
matchingMaxComparisons: HTMLInputElement; matchingMaxComparisons: HTMLInputElement;
@ -235,6 +251,7 @@ function getHTMLElementById(id: string): HTMLElement {
document.addEventListener('DOMContentLoaded', async () => { document.addEventListener('DOMContentLoaded', async () => {
// Improves browser compatibility // Improves browser compatibility
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('whatwg-fetch'); require('whatwg-fetch');
const drawAndUpdateUrl = async ( const drawAndUpdateUrl = async (
@ -259,6 +276,7 @@ document.addEventListener('DOMContentLoaded', async () => {
}, },
options: { options: {
outputFormat: getHTMLInputElementById('diff-url-options-output-format'), outputFormat: getHTMLInputElementById('diff-url-options-output-format'),
colorScheme: getHTMLInputElementById('diff-url-options-color-scheme'),
matching: getHTMLInputElementById('diff-url-options-matching'), matching: getHTMLInputElementById('diff-url-options-matching'),
wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'), wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'),
matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'), matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'),
@ -271,12 +289,13 @@ document.addEventListener('DOMContentLoaded', async () => {
let [config, diffString] = await prepareInitialState(elements); let [config, diffString] = await prepareInitialState(elements);
// Update HTML inputs from any changes in URL // Update HTML inputs from any changes in URL
config.outputFormat && (elements.options.outputFormat.value = config.outputFormat); if (config.outputFormat) elements.options.outputFormat.value = config.outputFormat;
config.drawFileList && (elements.checkboxes.drawFileList.checked = config.drawFileList); if (config.colorScheme) elements.options.colorScheme.value = config.colorScheme;
config.matching && (elements.options.matching.value = config.matching); if (config.drawFileList) elements.checkboxes.drawFileList.checked = config.drawFileList;
config.matchWordsThreshold && (elements.options.wordsThreshold.value = config.matchWordsThreshold.toString()); if (config.matching) elements.options.matching.value = config.matching;
config.matchingMaxComparisons && if (config.matchWordsThreshold) elements.options.wordsThreshold.value = config.matchWordsThreshold.toString();
(elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString()); if (config.matchingMaxComparisons)
elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString();
Object.entries(elements.options).forEach(([option, element]) => Object.entries(elements.options).forEach(([option, element]) =>
element.addEventListener('change', () => { 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> <span class="button clipboard" data-clipboard-text="npm install diff2html" title="Copy">Copy</span>
</div> </div>
<p> <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 Find usage examples in the Docs
</a> </a>
</p> </p>
@ -85,8 +85,8 @@
<div class="column"> <div class="column">
<h4 class="title is-size-4 is-spaced"><strong>With command line integration</strong></h4> <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 <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" way. Go here for the <a href="https://github.com/rtfpessoa/diff2html-cli#readme" target="_blank"
rel="noopener" rel="noreferrer"></a>full rel="noopener" rel="noreferrer">full
documentation</a>. documentation</a>.
</p> </p>
</div> </div>
@ -115,8 +115,46 @@
<hr> <hr>
<div id="users" class="container"> <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="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="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
@ -131,19 +169,21 @@
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
<p class="is-size-5 has-text-weight-bold">Codacy</p> <p class="is-size-5 has-text-weight-bold">Codacy</p>
</header> </header>
<section class="media-content"> <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> </section>
<footer> <footer>
<a href="https://www.codacy.com" target="_blank" rel="noopener" rel="noreferrer">Website</a> <a href="https://www.codacy.com" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
@ -158,6 +198,7 @@
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
@ -171,6 +212,7 @@
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
@ -180,91 +222,12 @@
<p>Show diffs between builds</p> <p>Show diffs between builds</p>
</section> </section>
<footer> <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> rel="noopener" rel="noreferrer">Website</a>
</footer> </footer>
</div> </div>
</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="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
@ -279,41 +242,28 @@
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
<p class="is-size-5 has-text-weight-bold">Chef Automate</p> <p class="is-size-5 has-text-weight-bold">Chef Automate</p>
</header> </header>
<section class="media-content"> <section class="media-content">
<p>full suite of enterprise capabilities for maintaining continuous visibility into application, <p>DevOps Dashboard for Complete Operational Visibility.</p>
infrastructure, and security automation.</p>
</section> </section>
<footer> <footer>
<a href="https://automate.chef.io/" target="_blank" rel="noopener" rel="noreferrer">Website</a> <a href="https://automate.chef.io/" target="_blank" rel="noopener" rel="noreferrer">Website</a>
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <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> </header>
<section class="media-content"> <section class="media-content">
<p>An integrated modeling solution for BPMN, DMN and CMMN based on bpmn.io.</p> <p>Detects dangerous and breaking changes in GraphQL schemas.</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>
</section> </section>
<footer> <footer>
<a href="https://github.com/fabsrc/graphql-schema-diff" target="_blank" rel="noopener" <a href="https://github.com/fabsrc/graphql-schema-diff" target="_blank" rel="noopener"
@ -321,13 +271,14 @@
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
<p class="is-size-5 has-text-weight-bold">cypress-plugin-snapshots</p> <p class="is-size-5 has-text-weight-bold">cypress-plugin-snapshots</p>
</header> </header>
<section class="media-content"> <section class="media-content">
<p>Plugin for snapshot tests in Cypress.io .</p> <p>Plugin for snapshot tests in Cypress.io.</p>
</section> </section>
<footer> <footer>
<a href="https://github.com/meinaart/cypress-plugin-snapshots" target="_blank" rel="noopener" <a href="https://github.com/meinaart/cypress-plugin-snapshots" target="_blank" rel="noopener"
@ -335,13 +286,14 @@
</footer> </footer>
</div> </div>
</div> </div>
<div class="column is-one-quarter-widescreen is-flex"> <div class="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
<p class="is-size-5 has-text-weight-bold">git-explorer</p> <p class="is-size-5 has-text-weight-bold">git-explorer</p>
</header> </header>
<section class="media-content"> <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> </section>
<footer> <footer>
<a href="https://github.com/thescientist13/git-explorer" target="_blank" rel="noopener" <a href="https://github.com/thescientist13/git-explorer" target="_blank" rel="noopener"
@ -349,34 +301,7 @@
</footer> </footer>
</div> </div>
</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="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
@ -391,20 +316,7 @@
</footer> </footer>
</div> </div>
</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="column is-one-quarter-widescreen is-flex">
<div class="box is-flex is-fullwidth is-vertical"> <div class="box is-flex is-fullwidth is-vertical">
<header> <header>
@ -419,6 +331,171 @@
</footer> </footer>
</div> </div>
</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>
</div> </div>
@ -433,9 +510,9 @@
<a href="https://gitter.im/rtfpessoa/diff2html" target="_blank" rel="noopener" rel="noreferrer">Gitter</a>. <a href="https://gitter.im/rtfpessoa/diff2html" target="_blank" rel="noopener" rel="noreferrer">Gitter</a>.
Need any help? Need any help?
</p> </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 Read more in the Docs
</a> </a>
</div> </div>
</section> </section>

View file

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

View file

@ -4,5 +4,4 @@ import '../../../main.ts';
import '../../../main.css'; import '../../../main.css';
import './index.css'; import './index.css';
// eslint-disable-next-line no-new
new Clipboard(document.getElementsByClassName('clipboard')[0]); 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>. <a href="https://twitter.com/rtfpessoa" target="_blank" rel="noopener" rel="noreferrer">@rtfpessoa</a>.
</p> </p>
<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> rel="noopener" rel="noreferrer">FAQ</a>
- -
<a class="footer-list-link" href="https://diff2html.xyz">diff2html</a> <a class="footer-list-link" href="https://diff2html.xyz">diff2html</a>
@ -102,4 +102,4 @@
</script> </script>
</body> </body>
</html> </html>

7962
yarn.lock

File diff suppressed because it is too large Load diff