Compare commits

..

No commits in common. "master" and "3.4.9" have entirely different histories.

55 changed files with 10283 additions and 22493 deletions

View file

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

228
.circleci/config.yml Normal file
View file

@ -0,0 +1,228 @@
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

58
.eslintrc.js Normal file
View file

@ -0,0 +1,58 @@
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',
},
};

View file

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

51
.github/workflows/codeql-analysis.yml vendored Normal file
View file

@ -0,0 +1,51 @@
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

View file

@ -1,35 +0,0 @@
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

View file

@ -1,148 +0,0 @@
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,18 +29,9 @@ bower_components/
# Terraform
/terraform/.terraform
# Compiled templates
/_target/
/src/diff2html-templates.*
# Compiled website
/docs/
# Bundles temporary typescript files compiled by webpack
/bundles-out/
# Web bundles
/bundles/
# CommonJS library
/lib/
# ESNext library
/lib-esm/

View file

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

View file

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

View file

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

164
README.md
View file

@ -1,20 +1,23 @@
# diff2html
[![npm](https://img.shields.io/npm/v/diff2html)](https://www.npmjs.com/package/diff2html)
[![node](https://img.shields.io/node/v/diff2html)](https://www.npmjs.com/package/diff2html)
[![npm](https://img.shields.io/npm/l/diff2html)](https://www.npmjs.com/package/diff2html)
[![GitHub Actions](https://github.com/rtfpessoa/diff2html/actions/workflows/release.yml/badge.svg)](https://github.com/rtfpessoa/diff2html/actions/workflows/release.yml)
[![npm 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)
[![Codacy Quality Badge](https://api.codacy.com/project/badge/Grade/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Grade)
[![Codacy Coverage Badge](https://api.codacy.com/project/badge/Coverage/06412dc3f5a14f568778d0db8a1f7dc8)](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Coverage)
[![CircleCI](https://circleci.com/gh/rtfpessoa/diff2html.svg?style=svg)](https://circleci.com/gh/rtfpessoa/diff2html)
[![npm](https://img.shields.io/npm/v/diff2html?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)
[![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.
[![NPM](https://nodei.co/npm/diff2html.png?downloads=true&downloadRank=true&stars=true)](https://nodei.co/npm/diff2html/)
## Table of Contents
<!-- toc -->
@ -153,7 +156,6 @@ draw(): void
synchronisedScroll(): void
fileListToggle(startVisible: boolean): void
highlightCode(): void
stickyFileHeaders(): void
```
### Diff2HtmlUI Configuration
@ -163,7 +165,6 @@ stickyFileHeaders(): void
- `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`
- `fileContentToggle`: allow each file contents to be toggled: `true` or `false`, default is `true`
- `stickyFileHeaders`: make file headers sticky: `true` or `false`, default is `true`
- [All the options](#diff2html-configuration) from Diff2Html are also valid configurations in Diff2HtmlUI
### Diff2HtmlUI Browser
@ -201,7 +202,7 @@ diff2htmlUi.draw();
```html
<!-- Stylesheet -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/11.8.0/styles/github.min.css" />
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.min.css" />
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/diff2html/bundles/css/diff2html.min.css" />
<!-- Javascripts -->
@ -227,21 +228,6 @@ 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
> Add the dependencies.
@ -268,7 +254,7 @@ document.addEventListener('DOMContentLoaded', () => {
#### Example with plain HTML+CSS+JS
```html
<!doctype html>
<!DOCTYPE html>
<html lang="en-us">
<head>
<meta charset="utf-8" />
@ -283,12 +269,12 @@ document.addEventListener('DOMContentLoaded', () => {
</head>
<script>
const diffString = `diff --git a/sample.js b/sample.js
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;
index 0000001..0ddf2ba
--- a/sample.js
+++ b/sample.js
@@ -1 +1 @@
-console.log("Hello World!")
+console.log("Hello from Diff2Html!")`;
document.addEventListener('DOMContentLoaded', function () {
var targetElement = document.getElementById('myDiffElement');
@ -314,41 +300,6 @@ index 0000001..0ddf2ba
</html>
```
#### StimulusJS with TypeScript
```ts
import { Controller } from '@hotwired/stimulus';
import { Diff2HtmlUI, Diff2HtmlUIConfig } from 'diff2html/lib/ui/js/diff2html-ui-slim.js';
// Requires `npm install highlight.js`
import 'highlight.js/styles/github.css';
import 'diff2html/bundles/css/diff2html.min.css';
export default class extends Controller {
connect(): void {
const diff2htmlUi = new Diff2HtmlUI(this.diffElement, this.unifiedDiff, this.diffConfiguration);
diff2htmlUi.draw();
}
get unifiedDiff(): string {
return this.data.get('unifiedDiff') || '';
}
get diffElement(): HTMLElement {
return this.element as HTMLElement;
}
get diffConfiguration(): Diff2HtmlUIConfig {
return {
drawFileList: true,
matching: 'lines',
};
}
}
```
## Diff2Html Usage
### Diff2Html API
@ -390,7 +341,7 @@ The HTML output accepts a Javascript object with configuration. Possible options
`false`
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is
`2500`
- `maxLineSizeInBlockForComparison`: maximum number of characters of the bigger line in a block to apply comparison,
- `maxLineSizeInBlockForComparison`: maximum number os characters of the bigger line in a block to apply comparison,
default is `200`
- `compiledTemplates`: object ([Hogan.js](https://github.com/twitter/hogan.js/) template values) with previously
compiled templates to replace parts of the html, default is `{}`. For example:
@ -399,10 +350,6 @@ 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 more information regarding the possible templates look into
> [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
- `highlightLanguages`: Map of extension to language name, used for highlighting. This overrides the default language
detection based on file extensions.
- `colorScheme`: color scheme to use for the diff, default is `light`. Possible values are `light`, `dark`, and `auto`
which will use the browser's preferred color scheme.
### Diff2Html Browser
@ -470,7 +417,7 @@ export class AppDiffComponent implements OnInit {
- HTML
```html
<!doctype html>
<!DOCTYPE html>
<html>
<head>
<title>diff2html</title>
@ -547,53 +494,42 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
<!-- markdownlint-disable -->
<table>
<tr>
<td align="center"><a href="https://rtfpessoa.xyz"><img src="https://avatars0.githubusercontent.com/u/902384?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rodrigo Fernandes</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=rtfpessoa" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/stockmind"><img src="https://avatars3.githubusercontent.com/u/5653847?v=4?s=100" width="100px;" alt=""/><br /><sub><b>stockmind</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=stockmind" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/lantian"><img src="https://avatars3.githubusercontent.com/u/535545?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ivan Vorontsov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=lantian" title="Code">💻</a></td>
<td align="center"><a href="http://www.nick-brewer.com"><img src="https://avatars1.githubusercontent.com/u/129300?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nick Brewer</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=brewern" title="Code">💻</a></td>
<td align="center"><a href="http://heyitsmattwade.com"><img src="https://avatars0.githubusercontent.com/u/8504000?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Matt Wade</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Aromellem" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=romellem" title="Code">💻</a></td>
<td align="center"><a href="http://mrfyda.github.io"><img src="https://avatars1.githubusercontent.com/u/593860?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Rafael Cortês</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=mrfyda" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nmatpt"><img src="https://avatars2.githubusercontent.com/u/5034733?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nuno Teixeira</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=nmatpt" title="Code">💻</a></td>
<td align="center"><a href="https://rtfpessoa.xyz"><img src="https://avatars0.githubusercontent.com/u/902384?v=4" width="100px;" alt=""/><br /><sub><b>Rodrigo Fernandes</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=rtfpessoa" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/stockmind"><img src="https://avatars3.githubusercontent.com/u/5653847?v=4" width="100px;" alt=""/><br /><sub><b>stockmind</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=stockmind" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/lantian"><img src="https://avatars3.githubusercontent.com/u/535545?v=4" width="100px;" alt=""/><br /><sub><b>Ivan Vorontsov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=lantian" title="Code">💻</a></td>
<td align="center"><a href="http://www.nick-brewer.com"><img src="https://avatars1.githubusercontent.com/u/129300?v=4" width="100px;" alt=""/><br /><sub><b>Nick Brewer</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=brewern" title="Code">💻</a></td>
<td align="center"><a href="http://heyitsmattwade.com"><img src="https://avatars0.githubusercontent.com/u/8504000?v=4" width="100px;" alt=""/><br /><sub><b>Matt Wade</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Aromellem" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://mrfyda.github.io"><img src="https://avatars1.githubusercontent.com/u/593860?v=4" width="100px;" alt=""/><br /><sub><b>Rafael Cortês</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=mrfyda" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/nmatpt"><img src="https://avatars2.githubusercontent.com/u/5034733?v=4" width="100px;" alt=""/><br /><sub><b>Nuno Teixeira</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=nmatpt" title="Code">💻</a></td>
</tr>
<tr>
<td align="center"><a href="https://saino.me/"><img src="https://avatars0.githubusercontent.com/u/1567423?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Koki Oyatsu</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Akaishuu0123" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=kaishuu0123" title="Code">💻</a></td>
<td align="center"><a href="http://www.jamesmonger.com"><img src="https://avatars2.githubusercontent.com/u/2037007?v=4?s=100" width="100px;" alt=""/><br /><sub><b>James Monger</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=Jameskmonger" title="Documentation">📖</a></td>
<td align="center"><a href="http://wesssel.github.io/"><img src="https://avatars2.githubusercontent.com/u/7767299?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Wessel van der Pal</b></sub></a><br /><a href="#security-wesssel" title="Security">🛡️</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=wesssel" title="Code">💻</a></td>
<td align="center"><a href="https://jung-kim.github.io"><img src="https://avatars2.githubusercontent.com/u/5281068?v=4?s=100" width="100px;" alt=""/><br /><sub><b>jk-kim</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=jung-kim" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/sss0791"><img src="https://avatars1.githubusercontent.com/u/1446970?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Sergey Semenov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Asss0791" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=sss0791" title="Code">💻</a></td>
<td align="center"><a href="http://researcher.watson.ibm.com/researcher/view.php?person=us-nickm"><img src="https://avatars3.githubusercontent.com/u/4741620?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Nick Mitchell</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Astarpit" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=starpit" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/samiraguiar"><img src="https://avatars0.githubusercontent.com/u/13439135?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Samir Aguiar</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=samiraguiar" title="Documentation">📖</a></td>
<td align="center"><a href="https://saino.me/"><img src="https://avatars0.githubusercontent.com/u/1567423?v=4" width="100px;" alt=""/><br /><sub><b>Koki Oyatsu</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Akaishuu0123" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://www.jamesmonger.com"><img src="https://avatars2.githubusercontent.com/u/2037007?v=4" width="100px;" alt=""/><br /><sub><b>James Monger</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=Jameskmonger" title="Documentation">📖</a></td>
<td align="center"><a href="http://wesssel.github.io/"><img src="https://avatars2.githubusercontent.com/u/7767299?v=4" width="100px;" alt=""/><br /><sub><b>Wessel van der Pal</b></sub></a><br /><a href="#security-wesssel" title="Security">🛡️</a></td>
<td align="center"><a href="https://jung-kim.github.io"><img src="https://avatars2.githubusercontent.com/u/5281068?v=4" width="100px;" alt=""/><br /><sub><b>jk-kim</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=jung-kim" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/sss0791"><img src="https://avatars1.githubusercontent.com/u/1446970?v=4" width="100px;" alt=""/><br /><sub><b>Sergey Semenov</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Asss0791" title="Bug reports">🐛</a></td>
<td align="center"><a href="http://researcher.watson.ibm.com/researcher/view.php?person=us-nickm"><img src="https://avatars3.githubusercontent.com/u/4741620?v=4" width="100px;" alt=""/><br /><sub><b>Nick Mitchell</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Astarpit" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/samiraguiar"><img src="https://avatars0.githubusercontent.com/u/13439135?v=4" width="100px;" alt=""/><br /><sub><b>Samir Aguiar</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=samiraguiar" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://twitter.com/pubkeypubkey"><img src="https://avatars3.githubusercontent.com/u/8926560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>pubkey</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=pubkey" title="Documentation">📖</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=pubkey" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/iliyaZelenko"><img src="https://avatars1.githubusercontent.com/u/13103045?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Илья</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=iliyaZelenko" title="Documentation">📖</a></td>
<td align="center"><a href="https://akr.am"><img src="https://avatars0.githubusercontent.com/u/1823771?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mohamed Akram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Amohd-akram" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=mohd-akram" title="Documentation">📖</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=mohd-akram" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/emarcotte"><img src="https://avatars0.githubusercontent.com/u/249390?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Eugene Marcotte</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=emarcotte" title="Code">💻</a></td>
<td align="center"><a href="http://twitter.com/dimasabanin"><img src="https://avatars0.githubusercontent.com/u/8316?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Dima Sabanin</b></sub></a><br /><a href="#maintenance-dsabanin" title="Maintenance">🚧</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=dsabanin" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/benabbottnz"><img src="https://avatars2.githubusercontent.com/u/2616473?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ben Abbott</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=benabbottnz" title="Documentation">📖</a></td>
<td align="center"><a href="http://webminer.js.org"><img src="https://avatars1.githubusercontent.com/u/2196373?v=4?s=100" width="100px;" alt=""/><br /><sub><b>弘树@阿里</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Adickeylth" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=dickeylth" title="Documentation">📖</a></td>
<td align="center"><a href="https://twitter.com/pubkeypubkey"><img src="https://avatars3.githubusercontent.com/u/8926560?v=4" width="100px;" alt=""/><br /><sub><b>pubkey</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=pubkey" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/iliyaZelenko"><img src="https://avatars1.githubusercontent.com/u/13103045?v=4" width="100px;" alt=""/><br /><sub><b>Илья</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=iliyaZelenko" title="Documentation">📖</a></td>
<td align="center"><a href="https://akr.am"><img src="https://avatars0.githubusercontent.com/u/1823771?v=4" width="100px;" alt=""/><br /><sub><b>Mohamed Akram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Amohd-akram" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/emarcotte"><img src="https://avatars0.githubusercontent.com/u/249390?v=4" width="100px;" alt=""/><br /><sub><b>Eugene Marcotte</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=emarcotte" title="Code">💻</a></td>
<td align="center"><a href="http://twitter.com/dimasabanin"><img src="https://avatars0.githubusercontent.com/u/8316?v=4" width="100px;" alt=""/><br /><sub><b>Dima Sabanin</b></sub></a><br /><a href="#maintenance-dsabanin" title="Maintenance">🚧</a></td>
<td align="center"><a href="https://github.com/benabbottnz"><img src="https://avatars2.githubusercontent.com/u/2616473?v=4" width="100px;" alt=""/><br /><sub><b>Ben Abbott</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=benabbottnz" title="Documentation">📖</a></td>
<td align="center"><a href="http://webminer.js.org"><img src="https://avatars1.githubusercontent.com/u/2196373?v=4" width="100px;" alt=""/><br /><sub><b>弘树@阿里</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Adickeylth" title="Bug reports">🐛</a></td>
</tr>
<tr>
<td align="center"><a href="https://github.com/Rantanen"><img src="https://avatars0.githubusercontent.com/u/385385?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Mikko Rantanen</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3ARantanen" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/extend1994"><img src="https://avatars2.githubusercontent.com/u/13430892?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Ann</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=extend1994" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/escitalopram"><img src="https://avatars0.githubusercontent.com/u/1155220?v=4?s=100" width="100px;" alt=""/><br /><sub><b>escitalopram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=escitalopram" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apps/dependabot"><img src="https://avatars0.githubusercontent.com/in/29110?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dependabot[bot]</b></sub></a><br /><a href="#security-dependabot[bot]" title="Security">🛡️</a> <a href="#maintenance-dependabot[bot]" title="Maintenance">🚧</a></td>
<td align="center"><a href="http://www.joshuakgoldberg.com"><img src="https://avatars1.githubusercontent.com/u/3335181?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Josh Goldberg</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=JoshuaKGoldberg" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apeckham"><img src="https://avatars.githubusercontent.com/u/14110?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Aaron</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=apeckham" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/pgrimaud"><img src="https://avatars.githubusercontent.com/u/1866496?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pierre Grimaud</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=pgrimaud" title="Documentation">📖</a></td>
</tr>
<tr>
<td align="center"><a href="https://domdomegg.github.io/"><img src="https://avatars.githubusercontent.com/u/4953590?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Adam Jones</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=domdomegg" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/charguer"><img src="https://avatars.githubusercontent.com/u/1830652?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Arthur Charguéraud</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=charguer" title="Documentation">📖</a></td>
<td align="center"><a href="https://twitter.com/pierrci"><img src="https://avatars.githubusercontent.com/u/5020707?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Pierric Cistac</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=Pierrci" title="Documentation">📖</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=Pierrci" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/xlith"><img src="https://avatars.githubusercontent.com/u/510560?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Civan Yavuzşen</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=xlith" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/timgates42"><img src="https://avatars.githubusercontent.com/u/47873678?v=4?s=100" width="100px;" alt=""/><br /><sub><b>Tim Gates</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=timgates42" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/campersau"><img src="https://avatars.githubusercontent.com/u/4009570?v=4?s=100" width="100px;" alt=""/><br /><sub><b>campersau</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=campersau" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apps/dependabot-preview"><img src="https://avatars.githubusercontent.com/in/2141?v=4?s=100" width="100px;" alt=""/><br /><sub><b>dependabot-preview[bot]</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=dependabot-preview[bot]" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/Rantanen"><img src="https://avatars0.githubusercontent.com/u/385385?v=4" width="100px;" alt=""/><br /><sub><b>Mikko Rantanen</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3ARantanen" title="Bug reports">🐛</a></td>
<td align="center"><a href="https://github.com/extend1994"><img src="https://avatars2.githubusercontent.com/u/13430892?v=4" width="100px;" alt=""/><br /><sub><b>Ann</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=extend1994" title="Documentation">📖</a></td>
<td align="center"><a href="https://github.com/escitalopram"><img src="https://avatars0.githubusercontent.com/u/1155220?v=4" width="100px;" alt=""/><br /><sub><b>escitalopram</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/issues?q=author%3Aescitalopram" title="Bug reports">🐛</a> <a href="https://github.com/rtfpessoa/diff2html/commits?author=escitalopram" title="Code">💻</a></td>
<td align="center"><a href="https://github.com/apps/dependabot"><img src="https://avatars0.githubusercontent.com/in/29110?v=4" width="100px;" alt=""/><br /><sub><b>dependabot[bot]</b></sub></a><br /><a href="#security-dependabot[bot]" title="Security">🛡️</a> <a href="#maintenance-dependabot[bot]" title="Maintenance">🚧</a></td>
<td align="center"><a href="http://www.joshuakgoldberg.com"><img src="https://avatars1.githubusercontent.com/u/3335181?v=4" width="100px;" alt=""/><br /><sub><b>Josh Goldberg</b></sub></a><br /><a href="https://github.com/rtfpessoa/diff2html/commits?author=JoshuaKGoldberg" title="Code">💻</a></td>
</tr>
</table>
<!-- markdownlint-restore -->
<!-- markdownlint-enable -->
<!-- prettier-ignore-end -->
<!-- ALL-CONTRIBUTORS-LIST:END -->

View file

@ -1,77 +0,0 @@
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,5 +19,4 @@ module.exports = {
lines: 93,
},
},
prettierPath: require.resolve('prettier-2'),
};

18121
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

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

View file

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

File diff suppressed because it is too large Load diff

File diff suppressed because one or more lines are too long

View file

@ -0,0 +1,176 @@
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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

@ -272,7 +272,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
const nxtLine = diffLines[lineIndex + 1];
const afterNxtLine = diffLines[lineIndex + 2];
if (line.startsWith('diff --git') || line.startsWith('diff --combined')) {
if (line.startsWith('diff')) {
startFile();
// diff --git a/blocked_delta_results.png b/blocked_delta_results.png
@ -290,22 +290,6 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
return;
}
if (line.startsWith('Binary files') && !currentFile?.isGitDiff) {
startFile();
const unixDiffBinaryStart = /^Binary files "?([a-ciow]\/.+)"? and "?([a-ciow]\/.+)"? differ/;
if ((values = unixDiffBinaryStart.exec(line))) {
possibleOldName = getFilename(values[1], undefined, config.dstPrefix);
possibleNewName = getFilename(values[2], undefined, config.srcPrefix);
}
if (currentFile === null) {
throw new Error('Where is my file !!!');
}
currentFile.isBinary = true;
return;
}
if (
!currentFile || // If we do not have a file yet, we should crete one
(!currentFile.isGitDiff &&
@ -458,16 +442,18 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
} else if ((values = index.exec(line))) {
currentFile.checksumBefore = values[1];
currentFile.checksumAfter = values[2];
if (values[3]) currentFile.mode = values[3];
values[3] && (currentFile.mode = values[3]);
} else if ((values = combinedIndex.exec(line))) {
currentFile.checksumBefore = [values[2], values[3]];
currentFile.checksumAfter = values[1];
} else if ((values = combinedMode.exec(line))) {
currentFile.oldMode = [values[2], values[3]];
currentFile.newMode = values[1];
// eslint-disable-next-line sonarjs/no-duplicated-branches
} else if ((values = combinedNewFile.exec(line))) {
currentFile.newFileMode = values[1];
currentFile.isNew = true;
// eslint-disable-next-line sonarjs/no-duplicated-branches
} else if ((values = combinedDeletedFile.exec(line))) {
currentFile.deletedFileMode = values[1];
currentFile.isDeleted = true;

View file

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

View file

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

View file

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

View file

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

View file

@ -2,15 +2,7 @@ import * as jsDiff from 'diff';
import { unifyPath, hashCode } from './utils';
import * as rematch from './rematch';
import {
ColorSchemeType,
DiffFile,
DiffFileName,
DiffLineParts,
DiffStyleType,
LineMatchingType,
LineType,
} from './types';
import { LineMatchingType, DiffStyleType, LineType, DiffLineParts, DiffFile, DiffFileName } from './types';
export type CSSLineClass =
| 'd2h-ins'
@ -45,7 +37,6 @@ export interface RenderConfig {
matchWordsThreshold?: number;
maxLineLengthHighlight?: number;
diffStyle?: DiffStyleType;
colorScheme?: ColorSchemeType;
}
export const defaultRenderConfig = {
@ -53,7 +44,6 @@ export const defaultRenderConfig = {
matchWordsThreshold: 0.25,
maxLineLengthHighlight: 10000,
diffStyle: DiffStyleType.WORD,
colorScheme: ColorSchemeType.LIGHT,
};
const separator = '/';
@ -86,18 +76,6 @@ 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
*/

View file

@ -52,10 +52,7 @@ export default class SideBySideRenderer {
})
.join('\n');
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', {
colorScheme: renderUtils.colorSchemeToCss(this.config.colorScheme),
content: diffsHtml,
});
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
}
makeFileDiffHtml(file: DiffFile, diffs: FileHtml): string {

View file

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

View file

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

View file

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

View file

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

View file

@ -5,80 +5,8 @@
*
*/
:root,
:host {
--d2h-bg-color: #fff;
--d2h-border-color: #ddd;
--d2h-dim-color: rgba(0, 0, 0, 0.3);
--d2h-line-border-color: #eeeeee;
--d2h-file-header-bg-color: #f7f7f7;
--d2h-file-header-border-color: #d8d8d8;
--d2h-empty-placeholder-bg-color: #f1f1f1;
--d2h-empty-placeholder-border-color: #e1e1e1;
--d2h-selected-color: #c8e1ff;
--d2h-ins-bg-color: #dfd;
--d2h-ins-border-color: #b4e2b4;
--d2h-ins-highlight-bg-color: #97f295;
--d2h-ins-label-color: #399839;
--d2h-del-bg-color: #fee8e9;
--d2h-del-border-color: #e9aeae;
--d2h-del-highlight-bg-color: #ffb6ba;
--d2h-del-label-color: #c33;
--d2h-change-del-color: #fdf2d0;
--d2h-change-ins-color: #ded;
--d2h-info-bg-color: #f8fafd;
--d2h-info-border-color: #d5e4f2;
--d2h-change-label-color: #d0b44c;
--d2h-moved-label-color: #3572b0;
/**
* Dark Color Scheme
*/
--d2h-dark-color: rgb(230, 237, 243);
--d2h-dark-bg-color: rgb(13, 17, 23);
--d2h-dark-border-color: rgb(48, 54, 61);
--d2h-dark-dim-color: rgb(110, 118, 129);
--d2h-dark-line-border-color: rgb(33, 38, 45);
--d2h-dark-file-header-bg-color: rgb(22, 27, 34);
--d2h-dark-file-header-border-color: rgb(48, 54, 61);
--d2h-dark-empty-placeholder-bg-color: rgba(110, 118, 129, 0.1);
--d2h-dark-empty-placeholder-border-color: rgb(48, 54, 61);
--d2h-dark-selected-color: rgba(56, 139, 253, 0.1);
--d2h-dark-ins-bg-color: rgba(46, 160, 67, 0.15);
--d2h-dark-ins-border-color: rgba(46, 160, 67, 0.4);
--d2h-dark-ins-highlight-bg-color: rgba(46, 160, 67, 0.4);
--d2h-dark-ins-label-color: rgb(63, 185, 80);
--d2h-dark-del-bg-color: rgba(248, 81, 73, 0.1);
--d2h-dark-del-border-color: rgba(248, 81, 73, 0.4);
--d2h-dark-del-highlight-bg-color: rgba(248, 81, 73, 0.4);
--d2h-dark-del-label-color: rgb(248, 81, 73);
--d2h-dark-change-del-color: rgba(210, 153, 34, 0.2);
--d2h-dark-change-ins-color: rgba(46, 160, 67, 0.25);
--d2h-dark-info-bg-color: rgba(56, 139, 253, 0.1);
--d2h-dark-info-border-color: rgba(56, 139, 253, 0.4);
--d2h-dark-change-label-color: rgb(210, 153, 34);
--d2h-dark-moved-label-color: #3572b0;
.d2h-d-none {
display: none;
}
.d2h-wrapper {
@ -89,17 +17,11 @@
display: flex;
height: 35px;
padding: 5px 10px;
border-bottom: 1px solid var(--d2h-file-header-border-color);
background-color: var(--d2h-file-header-bg-color);
border-bottom: 1px solid #d8d8d8;
background-color: #f7f7f7;
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 {
display: -webkit-box;
display: -ms-flexbox;
@ -110,18 +32,18 @@
.d2h-lines-added {
text-align: right;
border: 1px solid var(--d2h-ins-border-color);
border: 1px solid #b4e2b4;
border-radius: 5px 0 0 5px;
color: var(--d2h-ins-label-color);
color: #399839;
padding: 2px;
vertical-align: middle;
}
.d2h-lines-deleted {
text-align: left;
border: 1px solid var(--d2h-del-border-color);
border: 1px solid #e9aeae;
border-radius: 0 5px 5px 0;
color: var(--d2h-del-label-color);
color: #c33;
padding: 2px;
vertical-align: middle;
margin-left: 1px;
@ -145,7 +67,7 @@
}
.d2h-file-wrapper {
border: 1px solid var(--d2h-border-color);
border: 1px solid #ddd;
border-radius: 3px;
margin-bottom: 1em;
}
@ -157,12 +79,12 @@
font-size: 12px;
align-items: center;
border-radius: 3px;
border: 1px solid var(--d2h-border-color);
border: 1px solid #ddd;
padding: 4px 8px;
}
.d2h-file-collapse.d2h-selected {
background-color: var(--d2h-selected-color);
background-color: #c8e1ff;
}
.d2h-file-collapse-input {
@ -177,7 +99,7 @@
}
.d2h-files-diff {
display: flex;
display: block;
width: 100%;
}
@ -185,23 +107,20 @@
overflow-y: hidden;
}
.d2h-files-diff.d2h-d-none,
.d2h-file-diff.d2h-d-none {
display: none;
}
.d2h-file-side-diff {
display: inline-block;
overflow-x: scroll;
overflow-y: hidden;
width: 50%;
margin-right: -4px;
margin-bottom: -8px;
}
.d2h-code-line {
display: inline-block;
white-space: nowrap;
user-select: none;
width: calc(100% - 16em);
width: 100%;
/* Compensate for the absolute positioning of the line numbers */
padding: 0 8em;
}
@ -210,7 +129,7 @@
display: inline-block;
white-space: nowrap;
user-select: none;
width: calc(100% - 9em);
width: 100%;
/* Compensate for the absolute positioning of the line numbers */
padding: 0 4.5em;
}
@ -231,8 +150,9 @@
display: inline-block;
margin-top: -1px;
text-decoration: none;
background-color: var(--d2h-del-highlight-bg-color);
background-color: #ffb6ba;
border-radius: 0.2em;
vertical-align: middle;
}
.d2h-code-line ins,
@ -240,9 +160,10 @@
display: inline-block;
margin-top: -1px;
text-decoration: none;
background-color: var(--d2h-ins-highlight-bg-color);
background-color: #97f295;
border-radius: 0.2em;
text-align: left;
vertical-align: middle;
}
.d2h-code-line-prefix {
@ -277,10 +198,10 @@
/* Keep the numbers fixed on line contents scroll */
position: absolute;
display: inline-block;
background-color: var(--d2h-bg-color);
color: var(--d2h-dim-color);
background-color: #fff;
color: rgba(0, 0, 0, 0.3);
text-align: right;
border: solid var(--d2h-line-border-color);
border: solid #eeeeee;
border-width: 0 1px 0 1px;
cursor: pointer;
}
@ -295,10 +216,10 @@
display: inline-block;
box-sizing: border-box;
width: 4em;
background-color: var(--d2h-bg-color);
color: var(--d2h-dim-color);
background-color: #fff;
color: rgba(0, 0, 0, 0.3);
text-align: right;
border: solid var(--d2h-line-border-color);
border: solid #eeeeee;
border-width: 0 1px 0 1px;
cursor: pointer;
overflow: hidden;
@ -312,8 +233,8 @@
.d2h-code-side-emptyplaceholder,
.d2h-emptyplaceholder {
background-color: var(--d2h-empty-placeholder-bg-color);
border-color: var(--d2h-empty-placeholder-border-color);
background-color: #f1f1f1;
border-color: #e1e1e1;
}
.d2h-code-linenumber,
@ -333,27 +254,27 @@
*/
.d2h-del {
background-color: var(--d2h-del-bg-color);
border-color: var(--d2h-del-border-color);
background-color: #fee8e9;
border-color: #e9aeae;
}
.d2h-ins {
background-color: var(--d2h-ins-bg-color);
border-color: var(--d2h-ins-border-color);
background-color: #dfd;
border-color: #b4e2b4;
}
.d2h-info {
background-color: var(--d2h-info-bg-color);
color: var(--d2h-dim-color);
border-color: var(--d2h-info-border-color);
background-color: #f8fafd;
color: rgba(0, 0, 0, 0.3);
border-color: #d5e4f2;
}
.d2h-file-diff .d2h-del.d2h-change {
background-color: var(--d2h-change-del-color);
background-color: #fdf2d0;
}
.d2h-file-diff .d2h-ins.d2h-change {
background-color: var(--d2h-change-ins-color);
background-color: #ded;
}
/*
@ -366,11 +287,11 @@
.d2h-file-list-wrapper a {
text-decoration: none;
color: var(--d2h-moved-label-color);
color: #3572b0;
}
.d2h-file-list-wrapper a:visited {
color: var(--d2h-moved-label-color);
color: #3572b0;
}
.d2h-file-list-header {
@ -396,7 +317,7 @@
}
.d2h-file-list > li {
border-bottom: var(--d2h-border-color) solid 1px;
border-bottom: #ddd solid 1px;
padding: 5px 10px;
margin: 0;
}
@ -418,19 +339,19 @@
}
.d2h-deleted {
color: var(--d2h-del-label-color);
color: #c33;
}
.d2h-added {
color: var(--d2h-ins-label-color);
color: #399839;
}
.d2h-changed {
color: var(--d2h-change-label-color);
color: #d0b44c;
}
.d2h-moved {
color: var(--d2h-moved-label-color);
color: #3572b0;
}
.d2h-tag {
@ -440,302 +361,21 @@
font-size: 10px;
margin-left: 5px;
padding: 0 2px;
background-color: var(--d2h-bg-color);
background-color: #fff;
}
.d2h-deleted-tag {
border: var(--d2h-del-label-color) 1px solid;
border: #c33 1px solid;
}
.d2h-added-tag {
border: var(--d2h-ins-label-color) 1px solid;
border: #399839 1px solid;
}
.d2h-changed-tag {
border: var(--d2h-change-label-color) 1px solid;
border: #d0b44c 1px solid;
}
.d2h-moved-tag {
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;
}
border: #3572b0 1px solid;
}

View file

@ -1,4 +1,4 @@
import { closeTags, nodeStream, mergeStreams, getLanguage } from './highlight.js-helpers';
import { closeTags, nodeStream, mergeStreams } from './highlight.js-helpers';
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from '../../diff2html';
import { DiffFile } from '../../types';
@ -9,14 +9,12 @@ export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
highlight?: boolean;
fileListToggle?: boolean;
fileListStartVisible?: boolean;
highlightLanguages?: Map<string, string>;
/**
* @deprecated since version 3.1.0
* Smart selection is now enabled by default with vanilla CSS
*/
smartSelection?: boolean;
fileContentToggle?: boolean;
stickyFileHeaders?: boolean;
}
export const defaultDiff2HtmlUIConfig = {
@ -25,14 +23,12 @@ export const defaultDiff2HtmlUIConfig = {
highlight: true,
fileListToggle: true,
fileListStartVisible: false,
highlightLanguages: new Map<string, string>(),
/**
* @deprecated since version 3.1.0
* Smart selection is now enabled by default with vanilla CSS
*/
smartSelection: true,
fileContentToggle: true,
stickyFileHeaders: true,
};
export class Diff2HtmlUI {
@ -56,7 +52,6 @@ export class Diff2HtmlUI {
if (this.config.highlight) this.highlightCode();
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
if (this.config.fileContentToggle) this.fileContentToggle();
if (this.config.stickyFileHeaders) this.stickyFileHeaders();
}
synchronisedScroll(): void {
@ -137,43 +132,32 @@ export class Diff2HtmlUI {
}
highlightCode(): void {
const hljs = this.hljs;
if (hljs === null) {
if (this.hljs === null) {
throw new Error('Missing a `highlight.js` implementation. Please provide one when instantiating Diff2HtmlUI.');
}
// Collect all the diff files and execute the highlight on their lines
const files = this.targetElement.querySelectorAll('.d2h-file-wrapper');
files.forEach(file => {
// 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');
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';
}
const hljsLanguage = language ? this.hljs.getLanguage(language) : undefined;
// Collect all the code lines and execute the highlight on them
const codeLines = file.querySelectorAll('.d2h-code-line-ctn');
codeLines.forEach(line => {
// HACK: help Typescript know that `this.hljs` is defined since we already checked it
if (this.hljs === null) return;
const text = line.textContent;
const lineParent = line.parentNode;
if (text === null || lineParent === null || !this.isElement(lineParent)) return;
const result: HighlightResult = closeTags(
hljs.highlight(text, {
language: hljsLanguage,
this.hljs.highlight(text, {
language: hljsLanguage?.name || 'plaintext',
ignoreIllegals: true,
}),
);
@ -194,12 +178,6 @@ 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
*/

View file

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

View file

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

View file

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

View file

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

View file

@ -1,37 +1,28 @@
{
"include": ["src/**/*", "typings/**/*"],
"exclude": ["node_modules", "src/__tests__/**"],
"compilerOptions": {
"outDir": "bundles-out",
"module": "CommonJS",
"moduleResolution": "Node",
"target": "ES6",
"lib": ["ES6", "DOM"],
"jsx": "preserve",
"outDir": "./_target",
"target": "es5",
"module": "commonjs",
"moduleResolution": "node",
"lib": ["es2020", "dom"],
"allowJs": false,
"checkJs": false,
"importHelpers": false,
"esModuleInterop": true,
"allowSyntheticDefaultImports": true,
"strict": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"skipLibCheck": true,
"resolveJsonModule": true,
"declaration": true,
"declarationMap": true,
"sourceMap": true,
"noEmit": false,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"incremental": false,
"strictNullChecks": true,
"removeComments": true,
"preserveConstEnums": true,
"sourceMap": true,
"alwaysStrict": true,
"strict": true,
"noImplicitAny": true,
"noImplicitThis": true
}
"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,3 +1,4 @@
declare module 'merge' {
// eslint-disable-next-line @typescript-eslint/ban-types
export function recursive(clone: boolean, ...items: object[]): object;
}

View file

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

View file

@ -2,7 +2,7 @@
<div class="hero-body">
<div class="container">
<h1 class="title is-size-1 is-spaced">Demo<a href="#help">
<svg fill="currentColor" height="32" class="octicon octicon-unverified" viewBox="0 0 16 16" version="1.1" width="64"
<svg height="32" class="octicon octicon-unverified" viewBox="0 0 16 16" version="1.1" width="64"
aria-hidden="true">
<path
d="M15.67 7.06l-1.08-1.34c-.17-.22-.28-.48-.31-.77l-.19-1.7a1.51 1.51 0 0 0-1.33-1.33l-1.7-.19c-.3-.03-.56-.16-.78-.33L8.94.32c-.55-.44-1.33-.44-1.88 0L5.72 1.4c-.22.17-.48.28-.77.31l-1.7.19c-.7.08-1.25.63-1.33 1.33l-.19 1.7c-.03.3-.16.56-.33.78L.32 7.05c-.44.55-.44 1.33 0 1.88l1.08 1.34c.17.22.28.48.31.77l.19 1.7c.08.7.63 1.25 1.33 1.33l1.7.19c.3.03.56.16.78.33l1.34 1.08c.55.44 1.33.44 1.88 0l1.34-1.08c.22-.17.48-.28.77-.31l1.7-.19c.7-.08 1.25-.63 1.33-1.33l.19-1.7c.03-.3.16-.56.33-.78l1.08-1.34c.44-.55.44-1.33 0-1.88zM9 11.5c0 .28-.22.5-.5.5h-1c-.27 0-.5-.22-.5-.5v-1c0-.28.23-.5.5-.5h1c.28 0 .5.22.5.5v1zm1.56-4.89c-.06.17-.17.33-.3.47-.13.16-.14.19-.33.38-.16.17-.31.3-.52.45-.11.09-.2.19-.28.27-.08.08-.14.17-.19.27-.05.1-.08.19-.11.3-.03.11-.03.13-.03.25H7.13c0-.22 0-.31.03-.48.03-.19.08-.36.14-.52.06-.14.14-.28.25-.42.11-.13.23-.25.41-.38.27-.19.36-.3.48-.52.12-.22.2-.38.2-.59 0-.27-.06-.45-.2-.58-.13-.13-.31-.19-.58-.19-.09 0-.19.02-.3.05-.11.03-.17.09-.25.16-.08.07-.14.11-.2.2a.41.41 0 0 0-.09.28h-2c0-.38.13-.56.27-.83.16-.27.36-.5.61-.67.25-.17.55-.3.88-.38.33-.08.7-.13 1.09-.13.44 0 .83.05 1.17.13.34.09.63.22.88.39.23.17.41.38.55.63.13.25.19.55.19.88 0 .22 0 .42-.08.59l-.02-.01z">
@ -33,7 +33,7 @@
</div>
<div class="columns is-desktop is-multiline">
<div class="column is-one-sixth-widescreen">
<div class="column is-one-fifth-widescreen">
<label title="Output format of the HTML, either line by line or side by side">
<p>Output Format</p>
<select class="options-label-value" id="diff-url-options-output-format" name="outputFormat">
@ -42,24 +42,14 @@
</select>
</label>
</div>
<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">
<div class="column is-one-fifth-widescreen">
<label title="Show the file list summary before the diff">
<p>File Summary</p>
<input class="options-label-value" id="diff-url-options-show-files" type="checkbox" name="drawFileList"
checked />
</label>
</div>
<div class="column is-one-sixth-widescreen">
<div class="column is-one-fifth-widescreen">
<label title="Level of matching for the comparison algorithm">
<p>Matching Type</p>
<select class="options-label-value" id="diff-url-options-matching" name="matching">
@ -69,14 +59,14 @@
</select>
</label>
</div>
<div class="column is-one-sixth-widescreen">
<div class="column is-one-fifth-widescreen">
<label title="Similarity threshold for the matching algorithm">
<p>Words Threshold</p>
<input class="options-label-value" id="diff-url-options-match-words-threshold" type="number"
name="matchWordsThreshold" value="0.25" step="0.05" min="0" max="1" />
</label>
</div>
<div class="column is-one-sixth-widescreen">
<div class="column is-one-fifth-widescreen">
<label title="Maximum number of comparison performed by the matching algorithm in a block of changes">
<p>Max Comparisons</p>
<input class="options-label-value" id="diff-url-options-matching-max-comparisons" type="number"
@ -144,4 +134,4 @@
providing better diff support for existing online services.
</p>
</div>
</section>
</section>

View file

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

View file

@ -2,11 +2,9 @@ import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from '../../
import '../../../main.ts';
import '../../../main.css';
import './github-highlights.css';
import 'highlight.js/styles/github.css';
import '../../../../src/ui/css/diff2html.css';
import './demo.css';
import { colorSchemeToCss } from '../../../../src/render-utils';
import { ColorSchemeType } from '../../../../src/types';
/*
* Example URLs:
@ -24,7 +22,7 @@ import { ColorSchemeType } from '../../../../src/types';
type URLParams = {
diff?: string;
diffTooBigMessage?: string;
[key: string]: string | boolean | number | Map<string, string> | undefined;
[key: string]: string | boolean | number | undefined;
};
const searchParam = 'diff';
@ -123,16 +121,10 @@ function prepareRequest(url: string): Request {
function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
// 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 defaultColorScheme: ColorSchemeType =
window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches
? ColorSchemeType.DARK
: ColorSchemeType.LIGHT;
const config: URLParams = {
...defaultDiff2HtmlUIConfig,
colorScheme: defaultColorScheme,
...urlParamsRest,
};
@ -140,8 +132,8 @@ function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
const newObject = !Number.isNaN(Number(v))
? { [k]: Number(v) }
: v === 'true' || v === 'false'
? { [k]: Boolean(v) }
: { [k]: v };
? { [k]: Boolean(v) }
: { [k]: v };
return { ...object, ...newObject };
}, {});
}
@ -163,16 +155,9 @@ async function getDiff(request: Request): Promise<string> {
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
const diff2htmlUi = new Diff2HtmlUI(elements.structure.diffTarget, diffString, config);
setBodyColorScheme(diff2htmlUi.config.colorScheme);
diff2htmlUi.draw();
}
function setBodyColorScheme(colorScheme: ColorSchemeType): void {
document.body.className = colorSchemeToCss(colorScheme);
}
async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConfig, string]> {
const urlParams = getParamsFromSearch(window.location.search);
const currentUrl = (urlParams && urlParams[searchParam]) || 'https://github.com/rtfpessoa/diff2html/pull/106';
@ -215,7 +200,6 @@ type Elements = {
};
options: {
outputFormat: HTMLInputElement;
colorScheme: HTMLInputElement;
matching: HTMLInputElement;
wordsThreshold: HTMLInputElement;
matchingMaxComparisons: HTMLInputElement;
@ -251,7 +235,6 @@ function getHTMLElementById(id: string): HTMLElement {
document.addEventListener('DOMContentLoaded', async () => {
// Improves browser compatibility
// eslint-disable-next-line @typescript-eslint/no-require-imports
require('whatwg-fetch');
const drawAndUpdateUrl = async (
@ -276,7 +259,6 @@ document.addEventListener('DOMContentLoaded', async () => {
},
options: {
outputFormat: getHTMLInputElementById('diff-url-options-output-format'),
colorScheme: getHTMLInputElementById('diff-url-options-color-scheme'),
matching: getHTMLInputElementById('diff-url-options-matching'),
wordsThreshold: getHTMLInputElementById('diff-url-options-match-words-threshold'),
matchingMaxComparisons: getHTMLInputElementById('diff-url-options-matching-max-comparisons'),
@ -289,13 +271,12 @@ document.addEventListener('DOMContentLoaded', async () => {
let [config, diffString] = await prepareInitialState(elements);
// Update HTML inputs from any changes in URL
if (config.outputFormat) elements.options.outputFormat.value = config.outputFormat;
if (config.colorScheme) elements.options.colorScheme.value = config.colorScheme;
if (config.drawFileList) elements.checkboxes.drawFileList.checked = config.drawFileList;
if (config.matching) elements.options.matching.value = config.matching;
if (config.matchWordsThreshold) elements.options.wordsThreshold.value = config.matchWordsThreshold.toString();
if (config.matchingMaxComparisons)
elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString();
config.outputFormat && (elements.options.outputFormat.value = config.outputFormat);
config.drawFileList && (elements.checkboxes.drawFileList.checked = config.drawFileList);
config.matching && (elements.options.matching.value = config.matching);
config.matchWordsThreshold && (elements.options.wordsThreshold.value = config.matchWordsThreshold.toString());
config.matchingMaxComparisons &&
(elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString());
Object.entries(elements.options).forEach(([option, element]) =>
element.addEventListener('change', () => {

View file

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

View file

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

View file

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

View file

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

View file

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

7962
yarn.lock Normal file

File diff suppressed because it is too large Load diff