Merge pull request #257 from rtfpessoa/improve-build-configuration
clean: Improve build configurations
This commit is contained in:
commit
f1ff703e64
59 changed files with 2980 additions and 2325 deletions
|
|
@ -1,10 +0,0 @@
|
|||
# Skip build results
|
||||
_target/**
|
||||
coverage/**
|
||||
bundles/**
|
||||
docs/**
|
||||
lib/**
|
||||
lib-esm/**
|
||||
node_modules/**
|
||||
src/diff2html-templates.*
|
||||
typings/**
|
||||
58
.eslintrc.js
Normal file
58
.eslintrc.js
Normal 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',
|
||||
'prettier/@typescript-eslint',
|
||||
'prettier/babel',
|
||||
],
|
||||
plugins: ['@typescript-eslint', 'json', 'promise', 'import', 'node', 'sonarjs', 'jest', 'optimize-regex'],
|
||||
rules: {
|
||||
// Enable
|
||||
'optimize-regex/optimize-regex': 'error',
|
||||
// Hack: For some reason we need pass again the extensions
|
||||
'node/no-missing-import': [
|
||||
'error',
|
||||
{
|
||||
tryExtensions: ['.js', '.jsx', '.ts', '.tsx', '.json'],
|
||||
},
|
||||
],
|
||||
// Disable
|
||||
// https://github.com/benmosher/eslint-plugin-import/issues/1446
|
||||
'import/named': 'off',
|
||||
// We don't need this since we are using transpilation
|
||||
'node/no-unsupported-features/es-syntax': 'off',
|
||||
'no-process-exit': 'off',
|
||||
// Too verbose
|
||||
'sonarjs/no-duplicate-string': 'off',
|
||||
// Too verbose
|
||||
'sonarjs/cognitive-complexity': 'off',
|
||||
},
|
||||
};
|
||||
|
|
@ -1,30 +0,0 @@
|
|||
{
|
||||
"parser": "@typescript-eslint/parser",
|
||||
"parserOptions": {
|
||||
"ecmaVersion": 2018,
|
||||
"sourceType": "module",
|
||||
"ecmaFeatures": {
|
||||
"experimentalObjectRestSpread": true,
|
||||
"jsx": true
|
||||
}
|
||||
},
|
||||
"env": {
|
||||
"es6": true,
|
||||
"node": true,
|
||||
"browser": true,
|
||||
"commonjs": true
|
||||
},
|
||||
"plugins": ["standard", "node", "import", "promise", "@typescript-eslint", "jest"],
|
||||
"globals": {
|
||||
"document": false,
|
||||
"navigator": false,
|
||||
"window": false
|
||||
},
|
||||
"extends": [
|
||||
"plugin:@typescript-eslint/recommended",
|
||||
"plugin:jest/recommended",
|
||||
"plugin:promise/recommended",
|
||||
"standard",
|
||||
"plugin:prettier/recommended"
|
||||
]
|
||||
}
|
||||
40
.github/ISSUE_TEMPLATE.md
vendored
40
.github/ISSUE_TEMPLATE.md
vendored
|
|
@ -1,44 +1,44 @@
|
|||
### Step -1: Before filling an issue check out troubleshooting section
|
||||
|
||||
* Go to [README.md#Troubleshooting](https://github.com/rtfpessoa/diff2html#troubleshooting)
|
||||
- Go to [README.md#Troubleshooting](https://github.com/rtfpessoa/diff2html#troubleshooting)
|
||||
|
||||
### Step 0: Describe your environment
|
||||
|
||||
* OS: _____
|
||||
* diff2html version: _____
|
||||
* Using diff2html directly or using diff2html-ui helper: _____
|
||||
* Extra flags: _____
|
||||
- OS: **\_**
|
||||
- diff2html version: **\_**
|
||||
- Using diff2html directly or using diff2html-ui helper: **\_**
|
||||
- Extra flags: **\_**
|
||||
|
||||
### Step 1: Describe the problem:
|
||||
|
||||
#### Steps to reproduce:
|
||||
|
||||
1. _____
|
||||
2. _____
|
||||
3. _____
|
||||
1. ***
|
||||
2. ***
|
||||
3. ***
|
||||
|
||||
#### diff example:
|
||||
|
||||
```diff
|
||||
diff --git describe.c
|
||||
index fabadb8,cc95eb0..4866510
|
||||
--- a/describe.c
|
||||
+++ b/describe.c
|
||||
@@@ -98,20 -98,12 +98,20 @@@
|
||||
```diff
|
||||
diff --git describe.c
|
||||
index fabadb8,cc95eb0..4866510
|
||||
--- a/describe.c
|
||||
+++ b/describe.c
|
||||
@@@ -98,20 -98,12 +98,20 @@@
|
||||
return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;
|
||||
}
|
||||
```
|
||||
```
|
||||
|
||||
#### Observed Results:
|
||||
|
||||
* What happened? This could be a description, log output, etc.
|
||||
- What happened? This could be a description, log output, etc.
|
||||
|
||||
#### Expected Results:
|
||||
|
||||
* What did you expect to happen?
|
||||
- What did you expect to happen?
|
||||
|
||||
#### Relevant Code:
|
||||
|
||||
```
|
||||
// TODO(you): code here to reproduce the problem
|
||||
```
|
||||
```
|
||||
// TODO(you): code here to reproduce the problem
|
||||
```
|
||||
|
|
|
|||
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
31
.github/ISSUE_TEMPLATE/bug_report.md
vendored
|
|
@ -1,32 +1,23 @@
|
|||
---
|
||||
name: Bug report
|
||||
about: Create a report to help us improve
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Describe the bug**
|
||||
A clear and concise description of what the bug is.
|
||||
name: Bug report about: Create a report to help us improve title: "" labels: "" assignees: "" ---**Describe the bug** A
|
||||
clear and concise description of what the bug is.
|
||||
|
||||
**To Reproduce** Steps to reproduce the behavior:
|
||||
|
||||
**To Reproduce**
|
||||
Steps to reproduce the behavior:
|
||||
1. Go to '...'
|
||||
2. Click on '....'
|
||||
3. Scroll down to '....'
|
||||
4. See error
|
||||
|
||||
**Expected behavior**
|
||||
A clear and concise description of what you expected to happen.
|
||||
**Expected behavior** A clear and concise description of what you expected to happen.
|
||||
|
||||
**Screenshots**
|
||||
If applicable, add screenshots to help explain your problem.
|
||||
**Screenshots** If applicable, add screenshots to help explain your problem.
|
||||
|
||||
**Desktop (please complete the following information):**
|
||||
- OS: [e.g. Windows, Linux, Mac]
|
||||
- Browser [e.g. Firefox, Chrome, Safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context**
|
||||
Add any other context about the problem here.
|
||||
- OS: [e.g. Windows, Linux, Mac]
|
||||
- Browser [e.g. Firefox, Chrome, Safari]
|
||||
- Version [e.g. 22]
|
||||
|
||||
**Additional context** Add any other context about the problem here.
|
||||
|
|
|
|||
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
22
.github/ISSUE_TEMPLATE/feature_request.md
vendored
|
|
@ -1,20 +1,12 @@
|
|||
---
|
||||
name: Feature request
|
||||
about: Suggest an idea for this project
|
||||
title: ''
|
||||
labels: ''
|
||||
assignees: ''
|
||||
|
||||
---
|
||||
|
||||
**Is your feature request related to a problem? Please describe.**
|
||||
A clear and concise description of what the problem is. Ex. I'm always frustrated when [...]
|
||||
name: Feature request about: Suggest an idea for this project title: "" labels: "" assignees: "" ---**Is your feature
|
||||
request related to a problem? Please describe.** A clear and concise description of what the problem is. Ex. I'm always
|
||||
frustrated when [...]
|
||||
|
||||
**Describe the solution you'd like**
|
||||
A clear and concise description of what you want to happen.
|
||||
**Describe the solution you'd like** A clear and concise description of what you want to happen.
|
||||
|
||||
**Describe alternatives you've considered**
|
||||
A clear and concise description of any alternative solutions or features you've considered.
|
||||
**Describe alternatives you've considered** A clear and concise description of any alternative solutions or features
|
||||
you've considered.
|
||||
|
||||
**Additional context**
|
||||
Add any other context or screenshots about the feature request here.
|
||||
**Additional context** Add any other context or screenshots about the feature request here.
|
||||
|
|
|
|||
10
.github/workflows/ci.yml
vendored
10
.github/workflows/ci.yml
vendored
|
|
@ -31,17 +31,13 @@ jobs:
|
|||
${{ runner.os }}-yarn-
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Lint
|
||||
run: yarn run lint
|
||||
- name: Build
|
||||
run: yarn run build
|
||||
- name: Test
|
||||
run: yarn run coverage
|
||||
- name: Validate
|
||||
run: yarn run validate
|
||||
- name: Push coverage to Codacy
|
||||
if: matrix.node-version == '13.x'
|
||||
env:
|
||||
CODACY_PROJECT_TOKEN: ${{ secrets.CODACY_PROJECT_TOKEN }}
|
||||
run: yarn run codacy
|
||||
run: yarn run coverage:push
|
||||
- name: Save coverage report
|
||||
if: matrix.node-version == '13.x'
|
||||
uses: actions/upload-artifact@v1
|
||||
|
|
|
|||
8
.github/workflows/release.yml
vendored
8
.github/workflows/release.yml
vendored
|
|
@ -1,7 +1,8 @@
|
|||
name: Release
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches:
|
||||
- master
|
||||
|
||||
|
|
@ -12,6 +13,7 @@ jobs:
|
|||
image: codacy/git-version
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
if: github.event.pull_request.merged
|
||||
- name: Configure Git
|
||||
run: |
|
||||
git checkout -f "${GITHUB_REF#refs/heads/}"
|
||||
|
|
@ -46,7 +48,7 @@ jobs:
|
|||
path: tag.txt
|
||||
|
||||
publish:
|
||||
needs: [version, build]
|
||||
needs: [version]
|
||||
runs-on: ubuntu-18.04
|
||||
env:
|
||||
CI: true
|
||||
|
|
@ -84,7 +86,7 @@ jobs:
|
|||
git config user.email "$GITHUB_ACTOR@users.noreply.github.com"
|
||||
git config user.name "$GITHUB_ACTOR"
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
run: yarn
|
||||
- name: Prepare version
|
||||
env:
|
||||
GITHUB_TOKEN: ${{secrets.GITHUB_TOKEN}}
|
||||
|
|
|
|||
18
.github/workflows/website.yml
vendored
18
.github/workflows/website.yml
vendored
|
|
@ -1,7 +1,8 @@
|
|||
name: Website
|
||||
|
||||
on:
|
||||
push:
|
||||
pull_request:
|
||||
types: [closed]
|
||||
branches:
|
||||
- master
|
||||
|
||||
|
|
@ -15,6 +16,7 @@ jobs:
|
|||
node-version: [13.x]
|
||||
steps:
|
||||
- uses: actions/checkout@v1
|
||||
if: github.event.pull_request.merged
|
||||
- name: Setup Node.js ${{ matrix.node-version }}
|
||||
uses: actions/setup-node@v1
|
||||
with:
|
||||
|
|
@ -31,13 +33,11 @@ jobs:
|
|||
restore-keys: |
|
||||
${{ runner.os }}-yarn-
|
||||
- name: Install dependencies
|
||||
run: yarn install
|
||||
- name: Lint
|
||||
run: yarn run lint
|
||||
- name: Build
|
||||
run: yarn run build
|
||||
- name: Test
|
||||
run: yarn run coverage
|
||||
run: yarn
|
||||
- name: Build website
|
||||
run: |
|
||||
yarn run build:templates
|
||||
yarn run build:website
|
||||
- name: Save website artifact
|
||||
if: matrix.node-version == '13.x'
|
||||
uses: actions/upload-artifact@v1
|
||||
|
|
@ -59,5 +59,5 @@ jobs:
|
|||
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
|
||||
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
|
||||
run: |
|
||||
cd docs
|
||||
cd website
|
||||
aws s3 sync . s3://diff2html.xyz --region eu-west-1
|
||||
|
|
|
|||
4
.gitignore
vendored
4
.gitignore
vendored
|
|
@ -20,7 +20,7 @@ node_modules/
|
|||
npm-debug.log
|
||||
yarn-error.log
|
||||
|
||||
# Istanbul
|
||||
# Coverage
|
||||
coverage/
|
||||
|
||||
# Bower
|
||||
|
|
@ -29,7 +29,7 @@ bower_components/
|
|||
# Terraform
|
||||
/terraform/.terraform
|
||||
|
||||
/_target
|
||||
/_target/
|
||||
/src/diff2html-templates.*
|
||||
/docs/
|
||||
/bundles/
|
||||
|
|
|
|||
17
.prettierrc.json
Normal file
17
.prettierrc.json
Normal file
|
|
@ -0,0 +1,17 @@
|
|||
{
|
||||
"arrowParens": "avoid",
|
||||
"bracketSpacing": true,
|
||||
"htmlWhitespaceSensitivity": "css",
|
||||
"insertPragma": false,
|
||||
"jsxBracketSameLine": false,
|
||||
"jsxSingleQuote": false,
|
||||
"printWidth": 120,
|
||||
"proseWrap": "always",
|
||||
"quoteProps": "as-needed",
|
||||
"requirePragma": false,
|
||||
"semi": true,
|
||||
"singleQuote": true,
|
||||
"tabWidth": 2,
|
||||
"trailingComma": "all",
|
||||
"useTabs": false
|
||||
}
|
||||
|
|
@ -2,75 +2,60 @@
|
|||
|
||||
## Our Pledge
|
||||
|
||||
In the interest of fostering an open and welcoming environment, we as
|
||||
contributors and maintainers pledge to making participation in our project and
|
||||
our community a harassment-free experience for everyone, regardless of age, body
|
||||
size, disability, ethnicity, sex characteristics, gender identity and expression,
|
||||
level of experience, education, socio-economic status, nationality, personal
|
||||
appearance, race, religion, or sexual identity and orientation.
|
||||
In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making
|
||||
participation in our project and our community a harassment-free experience for everyone, regardless of age, body size,
|
||||
disability, ethnicity, sex characteristics, gender identity and expression, level of experience, education,
|
||||
socio-economic status, nationality, personal appearance, race, religion, or sexual identity and orientation.
|
||||
|
||||
## Our Standards
|
||||
|
||||
Examples of behavior that contributes to creating a positive environment
|
||||
include:
|
||||
Examples of behavior that contributes to creating a positive environment include:
|
||||
|
||||
* Using welcoming and inclusive language
|
||||
* Being respectful of differing viewpoints and experiences
|
||||
* Gracefully accepting constructive criticism
|
||||
* Focusing on what is best for the community
|
||||
* Showing empathy towards other community members
|
||||
- Using welcoming and inclusive language
|
||||
- Being respectful of differing viewpoints and experiences
|
||||
- Gracefully accepting constructive criticism
|
||||
- Focusing on what is best for the community
|
||||
- Showing empathy towards other community members
|
||||
|
||||
Examples of unacceptable behavior by participants include:
|
||||
|
||||
* The use of sexualized language or imagery and unwelcome sexual attention or
|
||||
advances
|
||||
* Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
* Public or private harassment
|
||||
* Publishing others' private information, such as a physical or electronic
|
||||
address, without explicit permission
|
||||
* Other conduct which could reasonably be considered inappropriate in a
|
||||
professional setting
|
||||
- The use of sexualized language or imagery and unwelcome sexual attention or advances
|
||||
- Trolling, insulting/derogatory comments, and personal or political attacks
|
||||
- Public or private harassment
|
||||
- Publishing others' private information, such as a physical or electronic address, without explicit permission
|
||||
- Other conduct which could reasonably be considered inappropriate in a professional setting
|
||||
|
||||
## Our Responsibilities
|
||||
|
||||
Project maintainers are responsible for clarifying the standards of acceptable
|
||||
behavior and are expected to take appropriate and fair corrective action in
|
||||
response to any instances of unacceptable behavior.
|
||||
Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take
|
||||
appropriate and fair corrective action in response to any instances of unacceptable behavior.
|
||||
|
||||
Project maintainers have the right and responsibility to remove, edit, or
|
||||
reject comments, commits, code, wiki edits, issues, and other contributions
|
||||
that are not aligned to this Code of Conduct, or to ban temporarily or
|
||||
permanently any contributor for other behaviors that they deem inappropriate,
|
||||
threatening, offensive, or harmful.
|
||||
Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits,
|
||||
issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any
|
||||
contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful.
|
||||
|
||||
## Scope
|
||||
|
||||
This Code of Conduct applies both within project spaces and in public spaces
|
||||
when an individual is representing the project or its community. Examples of
|
||||
representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed
|
||||
representative at an online or offline event. Representation of a project may be
|
||||
further defined and clarified by project maintainers.
|
||||
This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the
|
||||
project or its community. Examples of representing a project or community include using an official project e-mail
|
||||
address, posting via an official social media account, or acting as an appointed representative at an online or offline
|
||||
event. Representation of a project may be further defined and clarified by project maintainers.
|
||||
|
||||
## Enforcement
|
||||
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be
|
||||
reported by contacting the project team at rtfrodrigo [at] gmail [dot] com. All
|
||||
complaints will be reviewed and investigated and will result in a response that
|
||||
is deemed necessary and appropriate to the circumstances. The project team is
|
||||
obligated to maintain confidentiality with regard to the reporter of an incident.
|
||||
Further details of specific enforcement policies may be posted separately.
|
||||
Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the project team at
|
||||
rtfrodrigo [at] gmail [dot] com. All complaints will be reviewed and investigated and will result in a response that is
|
||||
deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with
|
||||
regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately.
|
||||
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good
|
||||
faith may face temporary or permanent repercussions as determined by other
|
||||
members of the project's leadership.
|
||||
Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent
|
||||
repercussions as determined by other members of the project's leadership.
|
||||
|
||||
## Attribution
|
||||
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
|
||||
available at https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at
|
||||
https://www.contributor-covenant.org/version/1/4/code-of-conduct.html
|
||||
|
||||
[homepage]: https://www.contributor-covenant.org
|
||||
|
||||
For answers to common questions about this code of conduct, see
|
||||
https://www.contributor-covenant.org/faq
|
||||
For answers to common questions about this code of conduct, see https://www.contributor-covenant.org/faq
|
||||
|
|
|
|||
|
|
@ -2,31 +2,33 @@
|
|||
|
||||
### Main rules
|
||||
|
||||
* Before you open a ticket or send a pull request, [search](https://github.com/rtfpessoa/diff2html/issues) for previous discussions about the same feature or issue. Add to the earlier ticket if you find one.
|
||||
- Before you open a ticket or send a pull request, [search](https://github.com/rtfpessoa/diff2html/issues) for previous
|
||||
discussions about the same feature or issue. Add to the earlier ticket if you find one.
|
||||
|
||||
* If you're proposing a new feature, make sure you create an issue to let other contributors know what you are working on.
|
||||
- If you're proposing a new feature, make sure you create an issue to let other contributors know what you are working
|
||||
on.
|
||||
|
||||
* Before sending a pull request make sure your code is tested.
|
||||
- Before sending a pull request make sure your code is tested.
|
||||
|
||||
* Before sending a pull request for a feature, be sure to run tests with `yarn test`.
|
||||
- Before sending a pull request for a feature, be sure to run tests with `yarn test`.
|
||||
|
||||
* Use the same coding style as the rest of the codebase, most of the check can be performed with `yarn run lint`.
|
||||
- Use the same coding style as the rest of the codebase, most of the check can be performed with `yarn run lint`.
|
||||
|
||||
* Use `git rebase` (not `git merge`) to sync your work from time to time with the master branch.
|
||||
- Use `git rebase` (not `git merge`) to sync your work from time to time with the master branch.
|
||||
|
||||
* After creating your pull request make sure the build is passing on [CircleCI](https://circleci.com/gh/rtfpessoa/diff2html)
|
||||
and that [Codacy](https://www.codacy.com/app/Codacy/diff2html) is also confident in the code quality.
|
||||
- After creating your pull request make sure the build is passing on
|
||||
[CircleCI](https://circleci.com/gh/rtfpessoa/diff2html) and that [Codacy](https://www.codacy.com/app/Codacy/diff2html)
|
||||
is also confident in the code quality.
|
||||
|
||||
* In your pull request, do not commit the `dist` or `build` folder if you needed to build the release files.
|
||||
- In your pull request, do not commit the `dist` or `build` folder if you needed to build the release files.
|
||||
|
||||
### Commit Style
|
||||
|
||||
Writing good commit logs is important. A commit log should describe what changed and why.
|
||||
Follow these guidelines when writing one:
|
||||
Writing good commit logs is important. A commit log should describe what changed and why. Follow these guidelines when
|
||||
writing one:
|
||||
|
||||
1. The first line should be 50 characters or less and contain a short
|
||||
description of the change prefixed with the name of the changed
|
||||
subsystem (e.g. "net: add localAddress and localPort to Socket").
|
||||
1. The first line should be 50 characters or less and contain a short description of the change prefixed with the name
|
||||
of the changed subsystem (e.g. "net: add localAddress and localPort to Socket").
|
||||
2. Keep the second line blank.
|
||||
3. Wrap all other lines at 72 columns.
|
||||
|
||||
|
|
@ -49,14 +51,11 @@ nicely even when it is indented.
|
|||
|
||||
By making a contribution to this project, I certify that:
|
||||
|
||||
* (a) The contribution was created in whole or in part by me and I
|
||||
have the right to submit it under the open source license indicated
|
||||
in the file; or
|
||||
* (b) The contribution is based upon previous work that, to the best
|
||||
of my knowledge, is covered under an appropriate open source license
|
||||
and I have the right under that license to submit that work with
|
||||
modifications, whether created in whole or in part by me, under the
|
||||
same open source license (unless I am permitted to submit under a
|
||||
different license), as indicated in the file; or
|
||||
* (c) The contribution was provided directly to me by some other
|
||||
person who certified (a), (b) or (c) and I have not modified it.
|
||||
- (a) The contribution was created in whole or in part by me and I have the right to submit it under the open source
|
||||
license indicated in the file; or
|
||||
- (b) The contribution is based upon previous work that, to the best of my knowledge, is covered under an appropriate
|
||||
open source license and I have the right under that license to submit that work with modifications, whether created in
|
||||
whole or in part by me, under the same open source license (unless I am permitted to submit under a different
|
||||
license), as indicated in the file; or
|
||||
- (c) The contribution was provided directly to me by some other person who certified (a), (b) or (c) and I have not
|
||||
modified it.
|
||||
|
|
|
|||
|
|
@ -1,12 +1,11 @@
|
|||
# Credits
|
||||
|
||||
This is the list of all the kind people that have contributed to the diff2html project.
|
||||
This list is ordered by first contribution.
|
||||
This is the list of all the kind people that have contributed to the diff2html project. This list is ordered by first
|
||||
contribution.
|
||||
|
||||
Thanks,
|
||||
@rtfpessoa
|
||||
Thanks, @rtfpessoa
|
||||
|
||||
----------
|
||||
---
|
||||
|
||||
Rodrigo Fernandes, [@rtfpessoa](https://github.com/rtfpessoa)
|
||||
|
||||
|
|
|
|||
26
LICENSE.md
26
LICENSE.md
|
|
@ -1,20 +1,14 @@
|
|||
Copyright 2014-2016 Rodrigo Fernandes https://rtfpessoa.github.io/
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
|
||||
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
|
||||
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit
|
||||
persons to whom the Software is furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
|
||||
Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
|
||||
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
|
||||
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
|
||||
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
|
|
|
|||
241
README.md
241
README.md
|
|
@ -2,20 +2,19 @@
|
|||
|
||||
[](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Grade)
|
||||
[](https://www.codacy.com/app/rtfpessoa/diff2html?utm_source=github.com&utm_medium=referral&utm_content=rtfpessoa/diff2html&utm_campaign=Badge_Coverage)
|
||||

|
||||
[](https://github.com/rtfpessoa/diff2html/actions?query=branch%3Amaster)
|
||||
|
||||
[](https://www.npmjs.com/package/diff2html)
|
||||
[](https://david-dm.org/rtfpessoa/diff2html)
|
||||
[](https://david-dm.org/rtfpessoa/diff2html#info=devDependencies)
|
||||
[](https://cdnjs.com/libraries/diff2html)
|
||||
|
||||
[]()
|
||||
[]()
|
||||
[]() []()
|
||||
[](https://www.npmjs.com/package/diff2html)
|
||||
[](#contributors-)
|
||||
[](https://gitter.im/rtfpessoa/diff2html?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge)
|
||||
|
||||
diff2html generates pretty HTML diffs from git or unified diff output.
|
||||
diff2html generates pretty HTML diffs from git diff or unified diff output.
|
||||
|
||||
[](https://nodei.co/npm/diff2html/)
|
||||
|
||||
|
|
@ -29,7 +28,7 @@ diff2html generates pretty HTML diffs from git or unified diff output.
|
|||
|
||||
- Inserted and removed lines
|
||||
|
||||
- GitHub like style
|
||||
- GitHub like visual style
|
||||
|
||||
- Code syntax highlight
|
||||
|
||||
|
|
@ -44,17 +43,39 @@ diff2html generates pretty HTML diffs from git or unified diff output.
|
|||
## Distributions
|
||||
|
||||
- [WebJar](http://www.webjars.org/)
|
||||
- [Node Module](https://www.npmjs.org/package/diff2html)
|
||||
- [Node CLI](https://www.npmjs.org/package/diff2html-cli)
|
||||
- [Node Library](https://www.npmjs.org/package/diff2html)
|
||||
- [NPM CLI](https://www.npmjs.org/package/diff2html-cli)
|
||||
- Manually download and import:
|
||||
- Browser
|
||||
- Browser / Bundle
|
||||
- Parser and HTML Generator
|
||||
- [bundles/js/diff2html.min.js](./bundles/js/diff2html.min.js) - includes the diff parser and html generator
|
||||
- [bundles/js/diff2html-ui.min.js](./bundles/js/diff2html-ui.min.js) - includes the wrapper of diff2html that adds highlight, synchronized scroll, and other nice features
|
||||
- Node.js
|
||||
- [lib/diff2html.js](./lib/diff2html.js) - targeted for es5, includes the diff parser and html generator
|
||||
- [lib-esm/diff2html.js](./lib-esm/diff2html.js) - targeted for es6 - includes the diff parser and html generator
|
||||
- Wrapper and helper adding syntax highlight, synchronized scroll, and other nice features
|
||||
- [bundles/js/diff2html-ui.min.js](./bundles/js/diff2html-ui.min.js) - includes the wrapper of diff2html with
|
||||
highlight for all `highlight.js` supported languages
|
||||
- [bundles/js/diff2html-ui-slim.min.js](./bundles/js/diff2html-ui-slim.min.js) - includes the wrapper of diff2html
|
||||
with "the most common" `highlight.js` supported languages
|
||||
- [bundles/js/diff2html-ui-base.min.js](./bundles/js/diff2html-ui-base.min.js) - includes the wrapper of diff2html
|
||||
without including a `highlight.js` implementation. You can use it without syntax highlight or by passing your
|
||||
own implementation with the languages you prefer
|
||||
- NPM / Node.js library
|
||||
- ES5
|
||||
- [lib/diff2html.js](./lib/diff2html.js) - includes the diff parser and html generator
|
||||
- [lib/ui/js/diff2html-ui.js](./lib/ui/js/diff2html-ui.js) - includes the wrapper of diff2html with highlight for
|
||||
all `highlight.js` supported languages
|
||||
- [lib/ui/js/diff2html-ui-slim.js](./lib/ui/js/diff2html-ui-slim.js) - includes the wrapper of diff2html with "the
|
||||
most common" `highlight.js` supported languages
|
||||
- [lib/ui/js/diff2html-ui-base.js](./lib/ui/js/diff2html-ui-base.js)
|
||||
- ES6
|
||||
- [lib-esm/diff2html.js](./lib-esm/diff2html.js) - includes the diff parser and html generator
|
||||
- [lib/ui/js/diff2html-ui.js](./lib/ui/js/diff2html-ui.js) - includes the wrapper of diff2html with highlight for
|
||||
all `highlight.js` supported languages
|
||||
- [lib/ui/js/diff2html-ui-slim.js](./lib/ui/js/diff2html-ui-slim.js) - includes the wrapper of diff2html with "the
|
||||
most common" `highlight.js` supported languages
|
||||
- [lib/ui/js/diff2html-ui-base.js](./lib/ui/js/diff2html-ui-base.js) - includes the wrapper of diff2html without
|
||||
including a `highlight.js` implementation. You can use it without syntax highlight or by passing your own
|
||||
implementation with the languages you prefer
|
||||
|
||||
## How to use
|
||||
## Diff2Html Usage
|
||||
|
||||
To load correctly in the Browser you always need to include the stylesheet in the final HTML.
|
||||
|
||||
|
|
@ -67,7 +88,41 @@ Import the stylesheet
|
|||
|
||||
You can also refer to it from a CDN like [CDNJS](https://cdnjs.com/libraries/diff2html).
|
||||
|
||||
### Browser Library
|
||||
### Diff2Html API
|
||||
|
||||
> JSON representation of the diff
|
||||
|
||||
function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): DiffFile[]
|
||||
|
||||
> Pretty HTML representation of the diff
|
||||
|
||||
function html(diffInput: string | DiffFile[], configuration: Diff2HtmlConfig = {}): string
|
||||
|
||||
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
|
||||
|
||||
### Diff2Html Configuration
|
||||
|
||||
The HTML output accepts a Javascript object with configuration. Possible options:
|
||||
|
||||
- `outputFormat`: the format of the output data: `'line-by-line'` or `'side-by-side'`, default is `'line-by-line'`
|
||||
- `drawFileList`: show a file list before the diff: `true` or `false`, default is `false`
|
||||
- `diffStyle`: show differences level in each line: `word` or `char`, default is `word`
|
||||
- `matching`: matching level: `'lines'` for matching lines, `'words'` for matching lines and words or `'none'`, default
|
||||
is `none`
|
||||
- `matchWordsThreshold`: similarity threshold for word matching, default is 0.25
|
||||
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is
|
||||
`2500`
|
||||
- `maxLineSizeInBlockForComparison`: maximum number os characters of the bigger line in a block to apply comparison,
|
||||
default is `200`
|
||||
- `maxLineLengthHighlight`: only perform diff changes highlight if lines are smaller than this, default is `10000`
|
||||
- `renderNothingWhenEmpty`: render nothing if the diff shows no change in its comparison: `true` or `false`, default is
|
||||
`false`
|
||||
- `compiledTemplates`: object with previously compiled templates to replace parts of the html
|
||||
- `rawTemplates`: object with raw not compiled templates to replace parts of the html
|
||||
> For more information regarding the possible templates look into
|
||||
> [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
|
||||
|
||||
### Diff2Html Browser
|
||||
|
||||
Import the stylesheet and the library code
|
||||
|
||||
|
|
@ -82,32 +137,34 @@ Import the stylesheet and the library code
|
|||
It will now be available as a global variable named `Diff2Html`.
|
||||
|
||||
```js
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
var diffHtml = global.Diff2Html.html("<Unified Diff String>", {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
var diffHtml = global.Diff2Html.html('<Unified Diff String>', {
|
||||
drawFileList: true,
|
||||
matching: "lines",
|
||||
outputFormat: "side-by-side"
|
||||
matching: 'lines',
|
||||
outputFormat: 'side-by-side',
|
||||
});
|
||||
document.getElementById("destination-elem-id").innerHTML = diffHtml;
|
||||
document.getElementById('destination-elem-id').innerHTML = diffHtml;
|
||||
});
|
||||
```
|
||||
|
||||
### Node Module
|
||||
### Diff2Html NPM / Node.js Library
|
||||
|
||||
```js
|
||||
const Diff2html = require("diff2html");
|
||||
const diffJson = Diff2html.parse("<Unified Diff String>");
|
||||
const Diff2html = require('diff2html');
|
||||
const diffJson = Diff2html.parse('<Unified Diff String>');
|
||||
const diffHtml = Diff2html.html(diffJson, { drawFileList: true });
|
||||
document.getElementById("destination-elem-id").innerHTML = diffHtml;
|
||||
document.getElementById('destination-elem-id').innerHTML = diffHtml;
|
||||
```
|
||||
|
||||
### Angular
|
||||
### Diff2Html Examples
|
||||
|
||||
#### Diff2Html Angular Example
|
||||
|
||||
- Typescript
|
||||
|
||||
```typescript
|
||||
import * as Diff2Html from "diff2html";
|
||||
import { Component, OnInit } from "@angular/core";
|
||||
import * as Diff2Html from 'diff2html';
|
||||
import { Component, OnInit } from '@angular/core';
|
||||
|
||||
export class AppDiffComponent implements OnInit {
|
||||
outputHtml: string;
|
||||
|
|
@ -119,8 +176,8 @@ export class AppDiffComponent implements OnInit {
|
|||
|
||||
init() {
|
||||
let strInput =
|
||||
"--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n";
|
||||
let outputHtml = Diff2Html.html(strInput, { drawFileList: true, matching: "lines" });
|
||||
'--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n';
|
||||
let outputHtml = Diff2Html.html(strInput, { drawFileList: true, matching: 'lines' });
|
||||
this.outputHtml = outputHtml;
|
||||
}
|
||||
}
|
||||
|
|
@ -148,7 +205,7 @@ export class AppDiffComponent implements OnInit {
|
|||
]
|
||||
```
|
||||
|
||||
### Vue.js
|
||||
#### Diff2Html Vue.js Example
|
||||
|
||||
```vue
|
||||
<template>
|
||||
|
|
@ -156,67 +213,30 @@ export class AppDiffComponent implements OnInit {
|
|||
</template>
|
||||
|
||||
<script>
|
||||
import * as Diff2Html from "diff2html";
|
||||
import "diff2html/bundles/css/diff2html.min.css";
|
||||
import * as Diff2Html from 'diff2html';
|
||||
import 'diff2html/bundles/css/diff2html.min.css';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
diffs:
|
||||
"--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n"
|
||||
'--- a/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n+++ b/server/vendor/golang.org/x/sys/unix/zsyscall_linux_mipsle.go\n@@ -1035,6 +1035,17 @@ func Prctl(option int, arg2 uintptr, arg3 uintptr, arg4 uintptr, arg5 uintptr) (\n \n // THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n \n+func Pselect(nfd int, r *FdSet, w *FdSet, e *FdSet, timeout *Timespec, sigmask *Sigset_t) (n int, err error) {\n+\tr0, _, e1 := Syscall6(SYS_PSELECT6, uintptr(nfd), uintptr(unsafe.Pointer(r)), uintptr(unsafe.Pointer(w)), uintptr(unsafe.Pointer(e)), uintptr(unsafe.Pointer(timeout)), uintptr(unsafe.Pointer(sigmask)))\n+\tn = int(r0)\n+\tif e1 != 0 {\n+\t\terr = errnoErr(e1)\n+\t}\n+\treturn\n+}\n+\n+// THIS FILE IS GENERATED BY THE COMMAND AT THE TOP; DO NOT EDIT\n+\n func read(fd int, p []byte) (n int, err error) {\n \tvar _p0 unsafe.Pointer\n \tif len(p) > 0 {\n',
|
||||
};
|
||||
},
|
||||
computed: {
|
||||
prettyHtml() {
|
||||
return Diff2Html.getPrettyHtml(this.diffs, {
|
||||
inputFormat: "diff",
|
||||
return Diff2Html.html(this.diffs, {
|
||||
drawFileList: true,
|
||||
matching: "lines",
|
||||
outputFormat: "side-by-side"
|
||||
matching: 'lines',
|
||||
outputFormat: 'side-by-side',
|
||||
});
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
</script>
|
||||
```
|
||||
|
||||
## API
|
||||
|
||||
> Intermediate Json From Git Word Diff Output
|
||||
|
||||
getJsonFromDiff(input: string, configuration?: Options): Result[]
|
||||
|
||||
> Pretty HTML diff
|
||||
|
||||
getPrettyHtml(input: any, configuration?: Options): string
|
||||
|
||||
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
|
||||
|
||||
## Configuration
|
||||
|
||||
The HTML output accepts a Javascript object with configuration. Possible options:
|
||||
|
||||
- `inputFormat`: the format of the input data: `'diff'` or `'json'`, default is `'diff'`
|
||||
- `outputFormat`: the format of the output data: `'line-by-line'` or `'side-by-side'`, default is `'line-by-line'`
|
||||
- `drawFileList`: show a file list before the diff: `true` or `false`, default is `false`
|
||||
- `diffStyle`: show differences level in each line: `word` or `char`, default is `word`
|
||||
- `matching`: matching level: `'lines'` for matching lines, `'words'` for matching lines and words or `'none'`, default is `none`
|
||||
- `matchWordsThreshold`: similarity threshold for word matching, default is 0.25
|
||||
- `matchingMaxComparisons`: perform at most this much comparisons for line matching a block of changes, default is `2500`
|
||||
- `maxLineSizeInBlockForComparison`: maximum number os characters of the bigger line in a block to apply comparison, default is `200`
|
||||
- `maxLineLengthHighlight`: only perform diff changes highlight if lines are smaller than this, default is `10000`
|
||||
- `compiledTemplates`: object with previously compiled templates to replace parts of the html
|
||||
- `rawTemplates`: object with raw not compiled templates to replace parts of the html
|
||||
- `renderNothingWhenEmpty`: render nothing if the diff shows no change in its comparison: `true` or `false`, default is `false`
|
||||
> For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
|
||||
|
||||
** Diff2HtmlUI Helper Options **
|
||||
|
||||
- `synchronisedScroll`: scroll both panes in side-by-side mode: `true` or `false`, default is `false`
|
||||
|
||||
> For more information regarding the possible templates look into [src/templates](https://github.com/rtfpessoa/diff2html/tree/master/src/templates)
|
||||
|
||||
## Diff2HtmlUI Helper
|
||||
## Diff2HtmlUI
|
||||
|
||||
> Simple wrapper to ease simple tasks in the browser such as: code highlight and js effects
|
||||
|
||||
|
|
@ -225,7 +245,41 @@ The HTML output accepts a Javascript object with configuration. Possible options
|
|||
- Enable collapsible file summary list
|
||||
- Enable syntax highlight of the code in the diffs
|
||||
|
||||
### How to use
|
||||
### Diff2HtmlUI API
|
||||
|
||||
> Create a Diff2HtmlUI instance
|
||||
|
||||
```ts
|
||||
constructor(diffInput: string | DiffFile[], target: HTMLElement) // diff2html-ui, diff2html-ui-slim
|
||||
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) // diff2html-ui-base
|
||||
```
|
||||
|
||||
> Generate and inject in the document the Pretty HTML representation of the diff
|
||||
|
||||
```ts
|
||||
draw(): void
|
||||
```
|
||||
|
||||
> Enable extra features
|
||||
|
||||
```ts
|
||||
synchronisedScroll(): void
|
||||
fileListToggle(startVisible: boolean): void
|
||||
highlightCode(): void
|
||||
```
|
||||
|
||||
> Check out the [docs/demo.html](./docs/demo.html) for a demo example.
|
||||
|
||||
### Diff2HtmlUI Configuration
|
||||
|
||||
- `synchronisedScroll`: scroll both panes in side-by-side mode: `true` or `false`, default is `true`
|
||||
- `highlight`: syntax highlight the code on the diff: `true` or `false`, default is `true`
|
||||
- `fileListToggle`: allow the file summary list to be toggled: `true` or `false`, default is `true`
|
||||
- `fileListStartVisible`: choose if the file summary list starts visible: `true` or `false`, default is `false`
|
||||
- `smartSelection`: allow selection of the code without including line numbers of line prefixes: `true` or `false`,
|
||||
default is `true`
|
||||
|
||||
### Diff2HtmlUI Browser
|
||||
|
||||
#### Mandatory HTML resource imports
|
||||
|
||||
|
|
@ -240,8 +294,8 @@ The HTML output accepts a Javascript object with configuration. Possible options
|
|||
#### Init
|
||||
|
||||
```js
|
||||
const targetElement = document.getElementById("destination-elem-id");
|
||||
const configuration = { drawFileList: true, matching: "lines" };
|
||||
const targetElement = document.getElementById('destination-elem-id');
|
||||
const configuration = { drawFileList: true, matching: 'lines' };
|
||||
|
||||
const diff2htmlUi = new Diff2HtmlUI(diffString, targetElement, configuration);
|
||||
// or
|
||||
|
|
@ -268,7 +322,7 @@ diff2htmlUi.draw();
|
|||
> Pass the option `highlight` with value true or invoke `diff2htmlUi.highlightCode()` after `diff2htmlUi.draw()`.
|
||||
|
||||
```js
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const diffString = `diff --git a/sample.js b/sample.js
|
||||
index 0000001..0ddf2ba
|
||||
--- a/sample.js
|
||||
|
|
@ -276,8 +330,8 @@ index 0000001..0ddf2ba
|
|||
@@ -1 +1 @@
|
||||
-console.log("Hello World!")
|
||||
+console.log("Hello from Diff2Html!")`;
|
||||
const targetElement = document.getElementById("myDiffElement");
|
||||
const configuration = { inputFormat: "json", drawFileList: true, matching: "lines", highlight: true };
|
||||
const targetElement = document.getElementById('myDiffElement');
|
||||
const configuration = { inputFormat: 'json', drawFileList: true, matching: 'lines', highlight: true };
|
||||
const diff2htmlUi = new Diff2HtmlUI(diffString, targetElement, configuration);
|
||||
diff2htmlUi.draw();
|
||||
diff2htmlUi.highlightCode();
|
||||
|
|
@ -293,19 +347,19 @@ index 0000001..0ddf2ba
|
|||
<script type="text/javascript" src="bundles/js/diff2html-ui.min.js"></script>
|
||||
```
|
||||
|
||||
> Invoke the Diff2HtmlUI helper
|
||||
> Pass the option `fileListToggle` with value true or invoke `diff2htmlUi.fileListToggle()` after `diff2htmlUi.draw()`.
|
||||
> Invoke the Diff2HtmlUI helper Pass the option `fileListToggle` with value true or invoke
|
||||
> `diff2htmlUi.fileListToggle()` after `diff2htmlUi.draw()`.
|
||||
|
||||
```js
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
const targetElement = document.getElementById("myDiffElement");
|
||||
var diff2htmlUi = new Diff2HtmlUI(lineDiffExample, targetElement, { drawFileList: true, matching: "lines" });
|
||||
document.addEventListener('DOMContentLoaded', () => {
|
||||
const targetElement = document.getElementById('myDiffElement');
|
||||
var diff2htmlUi = new Diff2HtmlUI(lineDiffExample, targetElement, { drawFileList: true, matching: 'lines' });
|
||||
diff2htmlUi.draw();
|
||||
diff2htmlUi.fileListToggle(false);
|
||||
});
|
||||
```
|
||||
|
||||
# Troubleshooting
|
||||
## Troubleshooting
|
||||
|
||||
### 1. Out of memory or Slow execution
|
||||
|
||||
|
|
@ -320,9 +374,8 @@ document.addEventListener("DOMContentLoaded", () => {
|
|||
|
||||
## Contributions
|
||||
|
||||
This is a developer friendly project, all the contributions are welcome.
|
||||
To contribute just send a pull request with your changes following the guidelines described in `CONTRIBUTING.md`.
|
||||
I will try to review them as soon as possible.
|
||||
This is a developer friendly project, all the contributions are welcome. To contribute just send a pull request with
|
||||
your changes following the guidelines described in `CONTRIBUTING.md`. I will try to review them as soon as possible.
|
||||
|
||||
## Contributors ✨
|
||||
|
||||
|
|
@ -369,14 +422,16 @@ Thanks goes to these wonderful people ([emoji key](https://allcontributors.org/d
|
|||
|
||||
<!-- ALL-CONTRIBUTORS-LIST:END -->
|
||||
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification. Contributions of any kind welcome!
|
||||
This project follows the [all-contributors](https://github.com/all-contributors/all-contributors) specification.
|
||||
Contributions of any kind welcome!
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2014-2016 Rodrigo Fernandes. Released under the terms of the MIT license.
|
||||
Copyright 2014-present Rodrigo Fernandes. Released under the terms of the MIT license.
|
||||
|
||||
## Thanks
|
||||
|
||||
This project is inspired in [pretty-diff](https://github.com/scottgonzalez/pretty-diff) by [Scott González](https://github.com/scottgonzalez).
|
||||
This project is inspired in [pretty-diff](https://github.com/scottgonzalez/pretty-diff) by
|
||||
[Scott González](https://github.com/scottgonzalez).
|
||||
|
||||
---
|
||||
|
|
|
|||
33
SECURITY.md
33
SECURITY.md
|
|
@ -9,34 +9,27 @@
|
|||
|
||||
## Reporting a Vulnerability
|
||||
|
||||
We take all security bugs in `diff2html` seriously.
|
||||
Thank you for the help improving the security of `diff2html`.
|
||||
We appreciate your efforts and responsible disclosure and
|
||||
will make every effort to acknowledge your contributions.
|
||||
We take all security bugs in `diff2html` seriously. Thank you for the help improving the security of `diff2html`. We
|
||||
appreciate your efforts and responsible disclosure and will make every effort to acknowledge your contributions.
|
||||
|
||||
Report security bugs by emailing the lead maintainer at `rtfrodrigo [at] gmail [dot] com`.
|
||||
|
||||
The lead maintainer will acknowledge your email within 48 hours, and will send a
|
||||
more detailed response within 48 hours indicating the next steps in handling
|
||||
your report. After the initial reply to your report, the security team will
|
||||
endeavor to keep you informed of the progress towards a fix and full
|
||||
announcement, and may ask for additional information or guidance.
|
||||
The lead maintainer will acknowledge your email within 48 hours, and will send a more detailed response within 48 hours
|
||||
indicating the next steps in handling your report. After the initial reply to your report, the security team will
|
||||
endeavor to keep you informed of the progress towards a fix and full announcement, and may ask for additional
|
||||
information or guidance.
|
||||
|
||||
Report security bugs in third-party modules to the person or team maintaining
|
||||
the module.
|
||||
Report security bugs in third-party modules to the person or team maintaining the module.
|
||||
|
||||
## Disclosure Policy
|
||||
|
||||
When the security team receives a security bug report, they will assign it to a
|
||||
primary handler. This person will coordinate the fix and release process,
|
||||
involving the following steps:
|
||||
When the security team receives a security bug report, they will assign it to a primary handler. This person will
|
||||
coordinate the fix and release process, involving the following steps:
|
||||
|
||||
* Confirm the problem and determine the affected versions.
|
||||
* Audit code to find any potential similar problems.
|
||||
* Prepare fixes for all releases still under maintenance. These fixes will be
|
||||
released as fast as possible.
|
||||
- Confirm the problem and determine the affected versions.
|
||||
- Audit code to find any potential similar problems.
|
||||
- Prepare fixes for all releases still under maintenance. These fixes will be released as fast as possible.
|
||||
|
||||
## Comments on this Policy
|
||||
|
||||
If you have suggestions on how this process could be improved please submit a
|
||||
pull request.
|
||||
If you have suggestions on how this process could be improved please submit a pull request.
|
||||
|
|
|
|||
|
|
@ -1,15 +1,22 @@
|
|||
module.exports = {
|
||||
verbose: true,
|
||||
preset: "ts-jest",
|
||||
testEnvironment: "node",
|
||||
coverageDirectory: "./coverage",
|
||||
coverageReporters: ["lcov", "text", "html"],
|
||||
preset: 'ts-jest',
|
||||
testEnvironment: 'node',
|
||||
coverageDirectory: './coverage',
|
||||
coverageReporters: ['lcov', 'text', 'html'],
|
||||
collectCoverageFrom: [
|
||||
'src/**/*.ts',
|
||||
'!src/ui/**',
|
||||
'!src/diff2html-templates.ts',
|
||||
'!src/__tests__/**',
|
||||
'!node_modules/**',
|
||||
],
|
||||
coverageThreshold: {
|
||||
global: {
|
||||
statements: 94,
|
||||
branches: 85,
|
||||
statements: 93,
|
||||
branches: 86,
|
||||
functions: 98,
|
||||
lines: 93
|
||||
}
|
||||
}
|
||||
lines: 93,
|
||||
},
|
||||
},
|
||||
};
|
||||
|
|
|
|||
87
package.json
87
package.json
|
|
@ -35,26 +35,51 @@
|
|||
"node": ">=10.13"
|
||||
},
|
||||
"scripts": {
|
||||
"lint": "eslint '*/**/*.{js,jsx,ts,tsx}'",
|
||||
"style": "yarn run lint",
|
||||
"test": "yarn run build-templates && jest",
|
||||
"coverage": "jest --collectCoverage",
|
||||
"coverage-html": "yarn run coverage && open ./coverage/index.html",
|
||||
"codacy": "cat ./coverage/lcov.info | codacy-coverage",
|
||||
"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; NODE_ENV=production WEBPACK_MINIMIZE=true webpack --mode production --config webpack.bundles.ts",
|
||||
"build-css": "rm -rf ./bundles/css; postcss --use autoprefixer postcss-import postcss-preset-env cssnano -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; NODE_ENV=production WEBPACK_MINIMIZE=true webpack --mode production --config webpack.website.ts",
|
||||
"start-website": "WEBPACK_MINIFY=false NODE_ENV=dev webpack-dev-server --mode dev --config webpack.website.ts",
|
||||
"preversion": "yarn run lint && yarn run build && yarn test",
|
||||
"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": "yarn run prettier --check",
|
||||
"format:fix": "yarn run prettier --write",
|
||||
"build": "yarn run build:css && yarn run build:templates && yarn run build:es5 && yarn run build:esm && yarn run build:bundles && yarn run build:website",
|
||||
"build:es5": "rm -rf lib; tsc -p tsconfig.json --outDir lib",
|
||||
"build:esm": "rm -rf lib-esm; tsc -p tsconfig.json -m es6 --outDir lib-esm",
|
||||
"build:bundles": "rm -rf ./bundles/js; webpack ---display-reasons --display-modules --mode production --config webpack.bundles.ts",
|
||||
"build:css": "rm -rf ./bundles/css; postcss --config ./postcss.config.js --no-map -o ./bundles/css/diff2html.min.css ./src/ui/css/diff2html.css",
|
||||
"build:templates": "ts-node ./scripts/hulk.ts --wrapper ts --variable 'defaultTemplates' ./src/templates/*.mustache > ./src/diff2html-templates.ts",
|
||||
"build:website": "rm -rf docs; webpack ---display-reasons --display-modules --mode production --config webpack.website.ts",
|
||||
"test": "is-ci 'test:coverage' 'test:watch'",
|
||||
"test:coverage": "jest --coverage",
|
||||
"test:watch": "jest --watch",
|
||||
"test:debug": "node --inspect-brk ./node_modules/jest/bin/jest.js --runInBand --watch",
|
||||
"coverage:open": "yarn run test:coverage && open ./coverage/index.html",
|
||||
"coverage:push": "cat ./coverage/lcov.info | codacy-coverage",
|
||||
"validate": "yarn run build:templates && yarn run format:check && yarn run lint:check && yarn run build && yarn run test:coverage",
|
||||
"fix": "yarn run format:fix && yarn run lint:fix",
|
||||
"start": "yarn run start:website",
|
||||
"start:website": "webpack-dev-server --mode development --config webpack.website.ts",
|
||||
"preversion": "yarn run validate",
|
||||
"version": "git add -A package.json"
|
||||
},
|
||||
"main": "./lib/diff2html.js",
|
||||
"module": "./lib-esm/diff2html.js",
|
||||
"types": "./lib/diff2html.d.ts",
|
||||
"husky": {
|
||||
"hooks": {
|
||||
"pre-commit": "lint-staged"
|
||||
}
|
||||
},
|
||||
"lint-staged": {
|
||||
"**/*.+(js|jsx|ts|tsx|json)": [
|
||||
"prettier --write",
|
||||
"eslint --fix",
|
||||
"git add"
|
||||
],
|
||||
"**/*.+(css|html|md|mdx)": [
|
||||
"prettier --write",
|
||||
"git add"
|
||||
]
|
||||
},
|
||||
"dependencies": {
|
||||
"diff": "4.0.1",
|
||||
"hogan.js": "3.0.2"
|
||||
|
|
@ -63,21 +88,20 @@
|
|||
"highlight.js": "9.17.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/autoprefixer": "9.6.1",
|
||||
"@types/clipboard": "2.0.1",
|
||||
"@types/copy-webpack-plugin": "5.0.0",
|
||||
"@types/diff": "4.0.2",
|
||||
"@types/highlight.js": "9.12.3",
|
||||
"@types/hogan.js": "3.0.0",
|
||||
"@types/html-webpack-plugin": "3.2.1",
|
||||
"@types/jest": "24.0.24",
|
||||
"@types/mini-css-extract-plugin": "0.8.0",
|
||||
"@types/jest": "24.0.25",
|
||||
"@types/mini-css-extract-plugin": "0.9.0",
|
||||
"@types/mkdirp": "0.5.2",
|
||||
"@types/node": "12.12.21",
|
||||
"@types/node": "13.1.1",
|
||||
"@types/nopt": "3.0.29",
|
||||
"@types/webpack": "4.41.0",
|
||||
"@typescript-eslint/eslint-plugin": "2.12.0",
|
||||
"@typescript-eslint/parser": "2.12.0",
|
||||
"@typescript-eslint/eslint-plugin": "2.13.0",
|
||||
"@typescript-eslint/parser": "2.13.0",
|
||||
"autoprefixer": "9.7.3",
|
||||
"bootstrap": "3.4.1",
|
||||
"clipboard": "2.0.4",
|
||||
|
|
@ -86,37 +110,38 @@
|
|||
"css-loader": "3.4.0",
|
||||
"cssnano": "4.1.10",
|
||||
"eslint": "6.8.0",
|
||||
"eslint-config-prettier": "6.7.0",
|
||||
"eslint-config-standard": "14.1.0",
|
||||
"eslint-config-prettier": "6.9.0",
|
||||
"eslint-plugin-import": "2.19.1",
|
||||
"eslint-plugin-jest": "23.1.1",
|
||||
"eslint-plugin-node": "10.0.0",
|
||||
"eslint-plugin-prettier": "3.1.2",
|
||||
"eslint-plugin-jest": "23.2.0",
|
||||
"eslint-plugin-json": "2.0.1",
|
||||
"eslint-plugin-node": "11.0.0",
|
||||
"eslint-plugin-optimize-regex": "1.1.7",
|
||||
"eslint-plugin-promise": "4.2.1",
|
||||
"eslint-plugin-standard": "4.0.1",
|
||||
"fast-html-parser": "1.0.1",
|
||||
"eslint-plugin-sonarjs": "0.5.0",
|
||||
"file-loader": "5.0.2",
|
||||
"handlebars": "4.5.3",
|
||||
"handlebars-loader": "1.7.1",
|
||||
"html-webpack-plugin": "3.2.0",
|
||||
"husky": "3.1.0",
|
||||
"image-webpack-loader": "6.0.0",
|
||||
"is-ci-cli": "2.0.0",
|
||||
"jest": "24.9.0",
|
||||
"lint-staged": "9.5.0",
|
||||
"mini-css-extract-plugin": "0.9.0",
|
||||
"mkdirp": "0.5.1",
|
||||
"nopt": "4.0.1",
|
||||
"postcss": "7.0.25",
|
||||
"postcss-cli": "6.1.3",
|
||||
"postcss-import": "12.0.1",
|
||||
"postcss-loader": "3.0.0",
|
||||
"postcss-normalize": "8.0.1",
|
||||
"postcss-preset-env": "6.7.0",
|
||||
"prettier": "1.19.1",
|
||||
"style-loader": "1.1.1",
|
||||
"ts-jest": "24.2.0",
|
||||
"ts-loader": "6.2.1",
|
||||
"ts-node": "8.5.4",
|
||||
"typescript": "3.7.4",
|
||||
"url-loader": "3.0.0",
|
||||
"webpack": "4.41.4",
|
||||
"webpack": "4.41.5",
|
||||
"webpack-cli": "3.3.10",
|
||||
"webpack-dev-server": "3.10.1",
|
||||
"whatwg-fetch": "3.0.0"
|
||||
|
|
|
|||
10
postcss.config.js
Normal file
10
postcss.config.js
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
module.exports = {
|
||||
sourceMap: false,
|
||||
plugins: {
|
||||
'postcss-import': {},
|
||||
'postcss-preset-env': {
|
||||
browsers: 'last 2 versions',
|
||||
},
|
||||
cssnano: {},
|
||||
},
|
||||
};
|
||||
|
|
@ -1,5 +1,3 @@
|
|||
#!/usr/bin/env node
|
||||
|
||||
/*
|
||||
* Copyright 2011 Twitter, Inc.
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
|
|
@ -15,12 +13,12 @@
|
|||
* limitations under the License.
|
||||
*/
|
||||
|
||||
import * as path from "path";
|
||||
import * as fs from "fs";
|
||||
import * as path from 'path';
|
||||
import * as fs from 'fs';
|
||||
|
||||
import * as hogan from "hogan.js";
|
||||
import nopt from "nopt";
|
||||
import * as mkderp from "mkdirp";
|
||||
import * as hogan from 'hogan.js';
|
||||
import nopt from 'nopt';
|
||||
import * as mkderp from 'mkdirp';
|
||||
|
||||
const options = nopt(
|
||||
{
|
||||
|
|
@ -29,47 +27,47 @@ const options = nopt(
|
|||
variable: String,
|
||||
wrapper: String,
|
||||
version: true,
|
||||
help: true
|
||||
help: true,
|
||||
},
|
||||
{
|
||||
n: ["--namespace"],
|
||||
o: ["--outputdir"],
|
||||
vn: ["--variable"],
|
||||
w: ["--wrapper"],
|
||||
h: ["--help"],
|
||||
v: ["--version"]
|
||||
}
|
||||
n: ['--namespace'],
|
||||
o: ['--outputdir'],
|
||||
vn: ['--variable'],
|
||||
w: ['--wrapper'],
|
||||
h: ['--help'],
|
||||
v: ['--version'],
|
||||
},
|
||||
);
|
||||
|
||||
const specials = ["/", ".", "*", "+", "?", "|", "(", ")", "[", "]", "{", "}", "\\"];
|
||||
const specialsRegExp = new RegExp("(\\" + specials.join("|\\") + ")", "g");
|
||||
const specials = ['/', '.', '*', '+', '?', '|', '(', ')', '[', ']', '{', '}', '\\'];
|
||||
const specialsRegExp = new RegExp('(\\' + specials.join('|\\') + ')', 'g');
|
||||
function escape(text: string): string {
|
||||
return text.replace(specialsRegExp, "\\$1");
|
||||
return text.replace(specialsRegExp, '\\$1');
|
||||
}
|
||||
|
||||
function cyan(text: string): string {
|
||||
return "\x1B[36m" + text + "\x1B[39m";
|
||||
return '\x1B[36m' + text + '\x1B[39m';
|
||||
}
|
||||
|
||||
function extractFiles(files: string[]): string[] {
|
||||
const usage = `${cyan(
|
||||
"USAGE:"
|
||||
'USAGE:',
|
||||
)} hulk [--wrapper wrapper] [--outputdir outputdir] [--namespace namespace] [--variable variable] FILES
|
||||
|
||||
${cyan("OPTIONS:")} [-w, --wrapper] :: wraps the template (i.e. amd)
|
||||
${cyan('OPTIONS:')} [-w, --wrapper] :: wraps the template (i.e. amd)
|
||||
[-o, --outputdir] :: outputs the templates as individual files to a directory
|
||||
|
||||
[-n, --namespace] :: prepend string to template names
|
||||
|
||||
[-vn, --variable] :: variable name for non-amd wrapper
|
||||
|
||||
${cyan("EXAMPLE:")} hulk --wrapper amd ./templates/*.mustache
|
||||
${cyan('EXAMPLE:')} hulk --wrapper amd ./templates/*.mustache
|
||||
|
||||
${cyan("NOTE:")} hulk supports the "*" wildcard and allows you to target specific extensions too
|
||||
${cyan('NOTE:')} hulk supports the "*" wildcard and allows you to target specific extensions too
|
||||
`;
|
||||
|
||||
if (options.version) {
|
||||
console.log(require("../package.json").version);
|
||||
console.log(require('../package.json').version);
|
||||
process.exit(0);
|
||||
}
|
||||
|
||||
|
|
@ -78,20 +76,18 @@ function extractFiles(files: string[]): string[] {
|
|||
process.exit(0);
|
||||
}
|
||||
|
||||
const templateFiles = files
|
||||
return files
|
||||
.map((fileGlob: string) => {
|
||||
if (/\*/.test(fileGlob)) {
|
||||
const [fileGlobPrefix, fileGlobSuffix] = fileGlob.split("*");
|
||||
const [fileGlobPrefix, fileGlobSuffix] = fileGlob.split('*');
|
||||
|
||||
const files = fs.readdirSync(fileGlobPrefix || ".").reduce<string[]>((previousFiles, relativeFilePath) => {
|
||||
return fs.readdirSync(fileGlobPrefix || '.').reduce<string[]>((previousFiles, relativeFilePath) => {
|
||||
const file = path.join(fileGlobPrefix, relativeFilePath);
|
||||
if (new RegExp(`${escape(fileGlobSuffix)}$`).test(relativeFilePath) && fs.statSync(file).isFile()) {
|
||||
previousFiles.push(file);
|
||||
}
|
||||
return previousFiles;
|
||||
}, []);
|
||||
|
||||
return files;
|
||||
} else if (fs.statSync(fileGlob).isFile()) {
|
||||
return [fileGlob];
|
||||
} else {
|
||||
|
|
@ -99,8 +95,6 @@ function extractFiles(files: string[]): string[] {
|
|||
}
|
||||
})
|
||||
.reduce((previous, current) => previous.concat(current), []);
|
||||
|
||||
return templateFiles;
|
||||
}
|
||||
|
||||
// Remove utf-8 byte order mark, http://en.wikipedia.org/wiki/Byte_order_mark
|
||||
|
|
@ -115,21 +109,21 @@ function removeByteOrderMark(text: string): string {
|
|||
function wrap(file: string, name: string, openedFile: string): string {
|
||||
const hoganTemplateString = `new Hogan.Template(${hogan.compile(openedFile, { asString: true })})`;
|
||||
|
||||
const objectName = options.variable || "templates";
|
||||
const objectName = options.variable || 'templates';
|
||||
const objectAccessor = `${objectName}["${name}"]`;
|
||||
const objectStmt = `${objectAccessor} = ${hoganTemplateString};`;
|
||||
|
||||
switch (options.wrapper) {
|
||||
case "amd":
|
||||
case 'amd':
|
||||
return `define(${
|
||||
!options.outputdir ? `"${path.join(path.dirname(file), name)}", ` : ""
|
||||
!options.outputdir ? `"${path.join(path.dirname(file), name)}", ` : ''
|
||||
}["hogan.js"], function(Hogan) { return ${hoganTemplateString}; });`;
|
||||
|
||||
case "node":
|
||||
case 'node':
|
||||
// If we have a template per file the export will expose the template directly
|
||||
return options.outputdir ? `global.${objectStmt};\nmodule.exports = ${objectAccessor};` : `global.${objectStmt}`;
|
||||
|
||||
case "ts":
|
||||
case 'ts':
|
||||
return `// @ts-ignore\n${objectStmt}`;
|
||||
default:
|
||||
return objectStmt;
|
||||
|
|
@ -137,25 +131,25 @@ function wrap(file: string, name: string, openedFile: string): string {
|
|||
}
|
||||
|
||||
function prepareOutput(content: string): string {
|
||||
const variableName = options.variable || "templates";
|
||||
const variableName = options.variable || 'templates';
|
||||
switch (options.wrapper) {
|
||||
case "amd":
|
||||
case 'amd':
|
||||
return content;
|
||||
case "node":
|
||||
case 'node':
|
||||
return `(function() {
|
||||
if (!!!global.${variableName}) global.${variableName} = {};
|
||||
var Hogan = require("hogan.js");
|
||||
${content}
|
||||
${!options.outputdir ? `module.exports = global.${variableName};\n` : ""})();`;
|
||||
${!options.outputdir ? `module.exports = global.${variableName};\n` : ''})();`;
|
||||
|
||||
case "ts":
|
||||
case 'ts':
|
||||
return `import * as Hogan from "hogan.js";
|
||||
type CompiledTemplates = { [name: string]: Hogan.Template };
|
||||
export const ${variableName}: CompiledTemplates = {};
|
||||
${content}`;
|
||||
|
||||
default:
|
||||
return "if (!!!" + variableName + ") var " + variableName + " = {};\n" + content;
|
||||
return 'if (!!!' + variableName + ') var ' + variableName + ' = {};\n' + content;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -166,28 +160,28 @@ if (options.outputdir) {
|
|||
|
||||
// Prepend namespace to template name
|
||||
function namespace(name: string): string {
|
||||
return (options.namespace || "") + name;
|
||||
return (options.namespace || '') + name;
|
||||
}
|
||||
|
||||
// Write a template foreach file that matches template extension
|
||||
const templates = extractFiles(options.argv.remain)
|
||||
.map(file => {
|
||||
const timmedFileContents = fs.readFileSync(file, "utf8").trim();
|
||||
const timmedFileContents = fs.readFileSync(file, 'utf8').trim();
|
||||
|
||||
if (!timmedFileContents) return;
|
||||
|
||||
const name = namespace(path.basename(file).replace(/\..*$/, ""));
|
||||
const name = namespace(path.basename(file).replace(/\..*$/, ''));
|
||||
const cleanFileContents = wrap(file, name, removeByteOrderMark(timmedFileContents));
|
||||
|
||||
if (!options.outputdir) return cleanFileContents;
|
||||
|
||||
const fileExtension = options.wrapper === "ts" ? "ts" : "js";
|
||||
const fileExtension = options.wrapper === 'ts' ? 'ts' : 'js';
|
||||
|
||||
return fs.writeFileSync(path.join(options.outputdir, `${name}.${fileExtension}`), prepareOutput(cleanFileContents));
|
||||
})
|
||||
.filter(templateContents => typeof templateContents !== "undefined");
|
||||
.filter(templateContents => typeof templateContents !== 'undefined');
|
||||
|
||||
// Output templates
|
||||
if (!templates.length || options.outputdir) process.exit(0);
|
||||
|
||||
console.log(prepareOutput(templates.join("\n")));
|
||||
console.log(prepareOutput(templates.join('\n')));
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
import { parse } from "../diff-parser";
|
||||
import { parse } from '../diff-parser';
|
||||
|
||||
describe("DiffParser", () => {
|
||||
describe("generateDiffJson", () => {
|
||||
describe('DiffParser', () => {
|
||||
describe('generateDiffJson', () => {
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it("should parse unix with \n diff", () => {
|
||||
it('should parse unix with \n diff', () => {
|
||||
const diff =
|
||||
"diff --git a/sample b/sample\n" +
|
||||
"index 0000001..0ddf2ba\n" +
|
||||
"--- a/sample\n" +
|
||||
"+++ b/sample\n" +
|
||||
"@@ -1 +1 @@\n" +
|
||||
"-test\n" +
|
||||
"+test1r\n";
|
||||
'diff --git a/sample b/sample\n' +
|
||||
'index 0000001..0ddf2ba\n' +
|
||||
'--- a/sample\n' +
|
||||
'+++ b/sample\n' +
|
||||
'@@ -1 +1 @@\n' +
|
||||
'-test\n' +
|
||||
'+test1r\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -53,15 +53,15 @@ describe("DiffParser", () => {
|
|||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it("should parse windows with \r\n diff", () => {
|
||||
it('should parse windows with \r\n diff', () => {
|
||||
const diff =
|
||||
"diff --git a/sample b/sample\r\n" +
|
||||
"index 0000001..0ddf2ba\r\n" +
|
||||
"--- a/sample\r\n" +
|
||||
"+++ b/sample\r\n" +
|
||||
"@@ -1 +1 @@\r\n" +
|
||||
"-test\r\n" +
|
||||
"+test1r\r\n";
|
||||
'diff --git a/sample b/sample\r\n' +
|
||||
'index 0000001..0ddf2ba\r\n' +
|
||||
'--- a/sample\r\n' +
|
||||
'+++ b/sample\r\n' +
|
||||
'@@ -1 +1 @@\r\n' +
|
||||
'-test\r\n' +
|
||||
'+test1r\r\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -103,15 +103,15 @@ describe("DiffParser", () => {
|
|||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it("should parse old os x with \r diff", () => {
|
||||
it('should parse old os x with \r diff', () => {
|
||||
const diff =
|
||||
"diff --git a/sample b/sample\r" +
|
||||
"index 0000001..0ddf2ba\r" +
|
||||
"--- a/sample\r" +
|
||||
"+++ b/sample\r" +
|
||||
"@@ -1 +1 @@\r" +
|
||||
"-test\r" +
|
||||
"+test1r\r";
|
||||
'diff --git a/sample b/sample\r' +
|
||||
'index 0000001..0ddf2ba\r' +
|
||||
'--- a/sample\r' +
|
||||
'+++ b/sample\r' +
|
||||
'@@ -1 +1 @@\r' +
|
||||
'-test\r' +
|
||||
'+test1r\r';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -153,15 +153,15 @@ describe("DiffParser", () => {
|
|||
});
|
||||
|
||||
// eslint-disable-next-line jest/expect-expect
|
||||
it("should parse mixed eols diff", () => {
|
||||
it('should parse mixed eols diff', () => {
|
||||
const diff =
|
||||
"diff --git a/sample b/sample\n" +
|
||||
"index 0000001..0ddf2ba\r\n" +
|
||||
"--- a/sample\r" +
|
||||
"+++ b/sample\r\n" +
|
||||
"@@ -1 +1 @@\n" +
|
||||
"-test\r" +
|
||||
"+test1r\n";
|
||||
'diff --git a/sample b/sample\n' +
|
||||
'index 0000001..0ddf2ba\r\n' +
|
||||
'--- a/sample\r' +
|
||||
'+++ b/sample\r\n' +
|
||||
'@@ -1 +1 @@\n' +
|
||||
'-test\r' +
|
||||
'+test1r\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -202,16 +202,16 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with special characters", () => {
|
||||
it('should parse diff with special characters', () => {
|
||||
const diff =
|
||||
'diff --git "a/bla with \ttab.scala" "b/bla with \ttab.scala"\n' +
|
||||
"index 4c679d7..e9bd385 100644\n" +
|
||||
'index 4c679d7..e9bd385 100644\n' +
|
||||
'--- "a/bla with \ttab.scala"\n' +
|
||||
'+++ "b/bla with \ttab.scala"\n' +
|
||||
"@@ -1 +1,2 @@\n" +
|
||||
"-cenas\n" +
|
||||
"+cenas com ananas\n" +
|
||||
"+bananas";
|
||||
'@@ -1 +1,2 @@\n' +
|
||||
'-cenas\n' +
|
||||
'+cenas com ananas\n' +
|
||||
'+bananas';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -259,16 +259,16 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with prefix", () => {
|
||||
it('should parse diff with prefix', () => {
|
||||
const diff =
|
||||
'diff --git "\tbla with \ttab.scala" "\tbla with \ttab.scala"\n' +
|
||||
"index 4c679d7..e9bd385 100644\n" +
|
||||
'index 4c679d7..e9bd385 100644\n' +
|
||||
'--- "\tbla with \ttab.scala"\n' +
|
||||
'+++ "\tbla with \ttab.scala"\n' +
|
||||
"@@ -1 +1,2 @@\n" +
|
||||
"-cenas\n" +
|
||||
"+cenas com ananas\n" +
|
||||
"+bananas";
|
||||
'@@ -1 +1,2 @@\n' +
|
||||
'-cenas\n' +
|
||||
'+cenas com ananas\n' +
|
||||
'+bananas';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -316,17 +316,17 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with deleted file", () => {
|
||||
it('should parse diff with deleted file', () => {
|
||||
const diff =
|
||||
"diff --git a/src/var/strundefined.js b/src/var/strundefined.js\n" +
|
||||
"deleted file mode 100644\n" +
|
||||
"index 04e16b0..0000000\n" +
|
||||
"--- a/src/var/strundefined.js\n" +
|
||||
"+++ /dev/null\n" +
|
||||
"@@ -1,3 +0,0 @@\n" +
|
||||
"-define(() => {\n" +
|
||||
"- return typeof undefined;\n" +
|
||||
"-});\n";
|
||||
'diff --git a/src/var/strundefined.js b/src/var/strundefined.js\n' +
|
||||
'deleted file mode 100644\n' +
|
||||
'index 04e16b0..0000000\n' +
|
||||
'--- a/src/var/strundefined.js\n' +
|
||||
'+++ /dev/null\n' +
|
||||
'@@ -1,3 +0,0 @@\n' +
|
||||
'-define(() => {\n' +
|
||||
'- return typeof undefined;\n' +
|
||||
'-});\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -375,19 +375,19 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with new file", () => {
|
||||
it('should parse diff with new file', () => {
|
||||
const diff =
|
||||
"diff --git a/test.js b/test.js\n" +
|
||||
"new file mode 100644\n" +
|
||||
"index 0000000..e1e22ec\n" +
|
||||
"--- /dev/null\n" +
|
||||
"+++ b/test.js\n" +
|
||||
"@@ -0,0 +1,5 @@\n" +
|
||||
'diff --git a/test.js b/test.js\n' +
|
||||
'new file mode 100644\n' +
|
||||
'index 0000000..e1e22ec\n' +
|
||||
'--- /dev/null\n' +
|
||||
'+++ b/test.js\n' +
|
||||
'@@ -0,0 +1,5 @@\n' +
|
||||
"+var parser = require('./source/git-parser');\n" +
|
||||
"+\n" +
|
||||
"+var patchLineList = [ false, false, false, false ];\n" +
|
||||
"+\n" +
|
||||
"+console.log(parser.parsePatchDiffResult(text, patchLineList));\n";
|
||||
'+\n' +
|
||||
'+var patchLineList = [ false, false, false, false ];\n' +
|
||||
'+\n' +
|
||||
'+console.log(parser.parsePatchDiffResult(text, patchLineList));\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -448,19 +448,19 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with nested diff", () => {
|
||||
it('should parse diff with nested diff', () => {
|
||||
const diff =
|
||||
"diff --git a/src/offset.js b/src/offset.js\n" +
|
||||
"index cc6ffb4..fa51f18 100644\n" +
|
||||
"--- a/src/offset.js\n" +
|
||||
"+++ b/src/offset.js\n" +
|
||||
"@@ -1,6 +1,5 @@\n" +
|
||||
'diff --git a/src/offset.js b/src/offset.js\n' +
|
||||
'index cc6ffb4..fa51f18 100644\n' +
|
||||
'--- a/src/offset.js\n' +
|
||||
'+++ b/src/offset.js\n' +
|
||||
'@@ -1,6 +1,5 @@\n' +
|
||||
"+var parser = require('./source/git-parser');\n" +
|
||||
"+\n" +
|
||||
'+\n' +
|
||||
"+var text = 'diff --git a/components/app/app.html b/components/app/app.html\\nindex ecb7a95..027bd9b 100644\\n--- a/components/app/app.html\\n+++ b/components/app/app.html\\n@@ -52,0 +53,3 @@\\n+\\n+\\n+\\n@@ -56,0 +60,3 @@\\n+\\n+\\n+\\n'\n" +
|
||||
"+var patchLineList = [ false, false, false, false ];\n" +
|
||||
"+\n" +
|
||||
"+console.log(parser.parsePatchDiffResult(text, patchLineList));\n";
|
||||
'+var patchLineList = [ false, false, false, false ];\n' +
|
||||
'+\n' +
|
||||
'+console.log(parser.parsePatchDiffResult(text, patchLineList));\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -526,32 +526,32 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with multiple blocks", () => {
|
||||
it('should parse diff with multiple blocks', () => {
|
||||
const diff =
|
||||
"diff --git a/src/attributes/classes.js b/src/attributes/classes.js\n" +
|
||||
"index c617824..c8d1393 100644\n" +
|
||||
"--- a/src/attributes/classes.js\n" +
|
||||
"+++ b/src/attributes/classes.js\n" +
|
||||
"@@ -1,10 +1,9 @@\n" +
|
||||
" define([\n" +
|
||||
'diff --git a/src/attributes/classes.js b/src/attributes/classes.js\n' +
|
||||
'index c617824..c8d1393 100644\n' +
|
||||
'--- a/src/attributes/classes.js\n' +
|
||||
'+++ b/src/attributes/classes.js\n' +
|
||||
'@@ -1,10 +1,9 @@\n' +
|
||||
' define([\n' +
|
||||
' "../core",\n' +
|
||||
' "../var/rnotwhite",\n' +
|
||||
'- "../var/strundefined",\n' +
|
||||
' "../data/var/dataPriv",\n' +
|
||||
' "../core/init"\n' +
|
||||
"-], function( jQuery, rnotwhite, strundefined, dataPriv ) {\n" +
|
||||
"+], function( jQuery, rnotwhite, dataPriv ) {\n" +
|
||||
" \n" +
|
||||
" var rclass = /[\\t\\r\\n\\f]/g;\n" +
|
||||
" \n" +
|
||||
"@@ -128,7 +127,7 @@ jQuery.fn.extend({\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
" // Toggle whole class name\n" +
|
||||
'-], function( jQuery, rnotwhite, strundefined, dataPriv ) {\n' +
|
||||
'+], function( jQuery, rnotwhite, dataPriv ) {\n' +
|
||||
' \n' +
|
||||
' var rclass = /[\\t\\r\\n\\f]/g;\n' +
|
||||
' \n' +
|
||||
'@@ -128,7 +127,7 @@ jQuery.fn.extend({\n' +
|
||||
' }\n' +
|
||||
' \n' +
|
||||
' // Toggle whole class name\n' +
|
||||
'- } else if ( type === strundefined || type === "boolean" ) {\n' +
|
||||
'+ } else if ( value === undefined || type === "boolean" ) {\n' +
|
||||
" if ( this.className ) {\n" +
|
||||
" // store className if set\n" +
|
||||
' if ( this.className ) {\n' +
|
||||
' // store className if set\n' +
|
||||
' dataPriv.set( this, "__className__", this.className );\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
|
|
@ -704,27 +704,27 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with multiple files", () => {
|
||||
it('should parse diff with multiple files', () => {
|
||||
const diff =
|
||||
"diff --git a/src/core/init.js b/src/core/init.js\n" +
|
||||
"index e49196a..50f310c 100644\n" +
|
||||
"--- a/src/core/init.js\n" +
|
||||
"+++ b/src/core/init.js\n" +
|
||||
"@@ -101,7 +101,7 @@ var rootjQuery,\n" +
|
||||
" // HANDLE: $(function)\n" +
|
||||
" // Shortcut for document ready\n" +
|
||||
" } else if ( jQuery.isFunction( selector ) ) {\n" +
|
||||
'diff --git a/src/core/init.js b/src/core/init.js\n' +
|
||||
'index e49196a..50f310c 100644\n' +
|
||||
'--- a/src/core/init.js\n' +
|
||||
'+++ b/src/core/init.js\n' +
|
||||
'@@ -101,7 +101,7 @@ var rootjQuery,\n' +
|
||||
' // HANDLE: $(function)\n' +
|
||||
' // Shortcut for document ready\n' +
|
||||
' } else if ( jQuery.isFunction( selector ) ) {\n' +
|
||||
'- return typeof rootjQuery.ready !== "undefined" ?\n' +
|
||||
"+ return rootjQuery.ready !== undefined ?\n" +
|
||||
" rootjQuery.ready( selector ) :\n" +
|
||||
" // Execute immediately if ready is not present\n" +
|
||||
" selector( jQuery );\n" +
|
||||
"diff --git a/src/event.js b/src/event.js\n" +
|
||||
"index 7336f4d..6183f70 100644\n" +
|
||||
"--- a/src/event.js\n" +
|
||||
"+++ b/src/event.js\n" +
|
||||
"@@ -1,6 +1,5 @@\n" +
|
||||
" define([\n" +
|
||||
'+ return rootjQuery.ready !== undefined ?\n' +
|
||||
' rootjQuery.ready( selector ) :\n' +
|
||||
' // Execute immediately if ready is not present\n' +
|
||||
' selector( jQuery );\n' +
|
||||
'diff --git a/src/event.js b/src/event.js\n' +
|
||||
'index 7336f4d..6183f70 100644\n' +
|
||||
'--- a/src/event.js\n' +
|
||||
'+++ b/src/event.js\n' +
|
||||
'@@ -1,6 +1,5 @@\n' +
|
||||
' define([\n' +
|
||||
' "./core",\n' +
|
||||
'- "./var/strundefined",\n' +
|
||||
' "./var/rnotwhite",\n' +
|
||||
|
|
@ -865,35 +865,35 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse combined diff", () => {
|
||||
it('should parse combined diff', () => {
|
||||
const diff =
|
||||
"diff --combined describe.c\n" +
|
||||
"index fabadb8,cc95eb0..4866510\n" +
|
||||
"--- a/describe.c\n" +
|
||||
"+++ b/describe.c\n" +
|
||||
"@@@ -98,20 -98,12 +98,20 @@@\n" +
|
||||
" return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
"- static void describe(char *arg)\n" +
|
||||
" -static void describe(struct commit *cmit, int last_one)\n" +
|
||||
"++static void describe(char *arg, int last_one)\n" +
|
||||
" {\n" +
|
||||
" + unsigned char sha1[20];\n" +
|
||||
" + struct commit *cmit;\n" +
|
||||
" struct commit_list *list;\n" +
|
||||
" static int initialized = 0;\n" +
|
||||
" struct commit_name *n;\n" +
|
||||
" \n" +
|
||||
" + if (get_sha1(arg, sha1) < 0)\n" +
|
||||
" + usage(describe_usage);\n" +
|
||||
" + cmit = lookup_commit_reference(sha1);\n" +
|
||||
" + if (!cmit)\n" +
|
||||
" + usage(describe_usage);\n" +
|
||||
" +\n" +
|
||||
" if (!initialized) {\n" +
|
||||
" initialized = 1;\n" +
|
||||
" for_each_ref(get_name);\n";
|
||||
'diff --combined describe.c\n' +
|
||||
'index fabadb8,cc95eb0..4866510\n' +
|
||||
'--- a/describe.c\n' +
|
||||
'+++ b/describe.c\n' +
|
||||
'@@@ -98,20 -98,12 +98,20 @@@\n' +
|
||||
' return (a_date > b_date) ? -1 : (a_date == b_date) ? 0 : 1;\n' +
|
||||
' }\n' +
|
||||
' \n' +
|
||||
'- static void describe(char *arg)\n' +
|
||||
' -static void describe(struct commit *cmit, int last_one)\n' +
|
||||
'++static void describe(char *arg, int last_one)\n' +
|
||||
' {\n' +
|
||||
' + unsigned char sha1[20];\n' +
|
||||
' + struct commit *cmit;\n' +
|
||||
' struct commit_list *list;\n' +
|
||||
' static int initialized = 0;\n' +
|
||||
' struct commit_name *n;\n' +
|
||||
' \n' +
|
||||
' + if (get_sha1(arg, sha1) < 0)\n' +
|
||||
' + usage(describe_usage);\n' +
|
||||
' + cmit = lookup_commit_reference(sha1);\n' +
|
||||
' + if (!cmit)\n' +
|
||||
' + usage(describe_usage);\n' +
|
||||
' +\n' +
|
||||
' if (!initialized) {\n' +
|
||||
' initialized = 1;\n' +
|
||||
' for_each_ref(get_name);\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1057,12 +1057,12 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diffs with copied files", () => {
|
||||
it('should parse diffs with copied files', () => {
|
||||
const diff =
|
||||
"diff --git a/index.js b/more-index.js\n" +
|
||||
"dissimilarity index 5%\n" +
|
||||
"copy from index.js\n" +
|
||||
"copy to more-index.js\n";
|
||||
'diff --git a/index.js b/more-index.js\n' +
|
||||
'dissimilarity index 5%\n' +
|
||||
'copy from index.js\n' +
|
||||
'copy to more-index.js\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1080,12 +1080,12 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diffs with moved files", () => {
|
||||
it('should parse diffs with moved files', () => {
|
||||
const diff =
|
||||
"diff --git a/more-index.js b/other-index.js\n" +
|
||||
"similarity index 86%\n" +
|
||||
"rename from more-index.js\n" +
|
||||
"rename to other-index.js\n";
|
||||
'diff --git a/more-index.js b/other-index.js\n' +
|
||||
'similarity index 86%\n' +
|
||||
'rename from more-index.js\n' +
|
||||
'rename to other-index.js\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1103,15 +1103,15 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diffs correct line numbers", () => {
|
||||
it('should parse diffs correct line numbers', () => {
|
||||
const diff =
|
||||
"diff --git a/sample b/sample\n" +
|
||||
"index 0000001..0ddf2ba\n" +
|
||||
"--- a/sample\n" +
|
||||
"+++ b/sample\n" +
|
||||
"@@ -1 +1,2 @@\n" +
|
||||
"-test\n" +
|
||||
"+test1r\n";
|
||||
'diff --git a/sample b/sample\n' +
|
||||
'index 0000001..0ddf2ba\n' +
|
||||
'--- a/sample\n' +
|
||||
'+++ b/sample\n' +
|
||||
'@@ -1 +1,2 @@\n' +
|
||||
'-test\n' +
|
||||
'+test1r\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1152,23 +1152,23 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse unified non git diff and strip timestamps off the headers", () => {
|
||||
it('should parse unified non git diff and strip timestamps off the headers', () => {
|
||||
const diffs = [
|
||||
// 2 hours ahead of GMT
|
||||
"--- a/sample.js 2016-10-25 11:37:14.000000000 +0200\n" +
|
||||
"+++ b/sample.js 2016-10-25 11:37:14.000000000 +0200\n" +
|
||||
"@@ -1 +1,2 @@\n" +
|
||||
"-test\n" +
|
||||
"+test1r\n" +
|
||||
"+test2r",
|
||||
'--- a/sample.js 2016-10-25 11:37:14.000000000 +0200\n' +
|
||||
'+++ b/sample.js 2016-10-25 11:37:14.000000000 +0200\n' +
|
||||
'@@ -1 +1,2 @@\n' +
|
||||
'-test\n' +
|
||||
'+test1r\n' +
|
||||
'+test2r',
|
||||
// 2 hours behind GMT
|
||||
"--- a/sample.js 2016-10-25 11:37:14.000000000 -0200\n" +
|
||||
"+++ b/sample.js 2016-10-25 11:37:14.000000000 -0200\n" +
|
||||
"@@ -1 +1,2 @@\n" +
|
||||
"-test\n" +
|
||||
"+test1r\n" +
|
||||
"+test2r"
|
||||
].join("\n");
|
||||
'--- a/sample.js 2016-10-25 11:37:14.000000000 -0200\n' +
|
||||
'+++ b/sample.js 2016-10-25 11:37:14.000000000 -0200\n' +
|
||||
'@@ -1 +1,2 @@\n' +
|
||||
'-test\n' +
|
||||
'+test1r\n' +
|
||||
'+test2r',
|
||||
].join('\n');
|
||||
const result = parse(diffs);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1248,9 +1248,9 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse unified non git diff", () => {
|
||||
it('should parse unified non git diff', () => {
|
||||
const diff =
|
||||
"--- a/sample.js\n" + "+++ b/sample.js\n" + "@@ -1 +1,2 @@\n" + "-test\n" + "+test1r\n" + "+test2r\n";
|
||||
'--- a/sample.js\n' + '+++ b/sample.js\n' + '@@ -1 +1,2 @@\n' + '-test\n' + '+test1r\n' + '+test2r\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1294,18 +1294,18 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse unified diff with multiple hunks and files", () => {
|
||||
it('should parse unified diff with multiple hunks and files', () => {
|
||||
const diff =
|
||||
"--- sample.js\n" +
|
||||
"+++ sample.js\n" +
|
||||
"@@ -1 +1,2 @@\n" +
|
||||
"-test\n" +
|
||||
"@@ -10 +20,2 @@\n" +
|
||||
"+test\n" +
|
||||
"--- sample1.js\n" +
|
||||
"+++ sample1.js\n" +
|
||||
"@@ -1 +1,2 @@\n" +
|
||||
"+test1";
|
||||
'--- sample.js\n' +
|
||||
'+++ sample.js\n' +
|
||||
'@@ -1 +1,2 @@\n' +
|
||||
'-test\n' +
|
||||
'@@ -10 +20,2 @@\n' +
|
||||
'+test\n' +
|
||||
'--- sample1.js\n' +
|
||||
'+++ sample1.js\n' +
|
||||
'@@ -1 +1,2 @@\n' +
|
||||
'+test1';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1375,20 +1375,20 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with --- and +++ in the context lines", () => {
|
||||
it('should parse diff with --- and +++ in the context lines', () => {
|
||||
const diff =
|
||||
"--- sample.js\n" +
|
||||
"+++ sample.js\n" +
|
||||
"@@ -1,8 +1,8 @@\n" +
|
||||
" test\n" +
|
||||
" \n" +
|
||||
"-- 1\n" +
|
||||
"--- 1\n" +
|
||||
"---- 1\n" +
|
||||
" \n" +
|
||||
"++ 2\n" +
|
||||
"+++ 2\n" +
|
||||
"++++ 2";
|
||||
'--- sample.js\n' +
|
||||
'+++ sample.js\n' +
|
||||
'@@ -1,8 +1,8 @@\n' +
|
||||
' test\n' +
|
||||
' \n' +
|
||||
'-- 1\n' +
|
||||
'--- 1\n' +
|
||||
'---- 1\n' +
|
||||
' \n' +
|
||||
'++ 2\n' +
|
||||
'+++ 2\n' +
|
||||
'++++ 2';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1468,8 +1468,8 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff without proper hunk headers", () => {
|
||||
const diff = "--- sample.js\n" + "+++ sample.js\n" + "@@ @@\n" + " test";
|
||||
it('should parse diff without proper hunk headers', () => {
|
||||
const diff = '--- sample.js\n' + '+++ sample.js\n' + '@@ @@\n' + ' test';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1501,13 +1501,13 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse binary file diff", () => {
|
||||
it('should parse binary file diff', () => {
|
||||
const diff =
|
||||
"diff --git a/last-changes-config.png b/last-changes-config.png\n" +
|
||||
"index 322248b..56fc1f2 100644\n" +
|
||||
"--- a/last-changes-config.png\n" +
|
||||
"+++ b/last-changes-config.png\n" +
|
||||
"Binary files differ";
|
||||
'diff --git a/last-changes-config.png b/last-changes-config.png\n' +
|
||||
'index 322248b..56fc1f2 100644\n' +
|
||||
'--- a/last-changes-config.png\n' +
|
||||
'+++ b/last-changes-config.png\n' +
|
||||
'Binary files differ';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1536,21 +1536,21 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with --find-renames", () => {
|
||||
it('should parse diff with --find-renames', () => {
|
||||
const diff =
|
||||
"diff --git a/src/test-bar.js b/src/test-baz.js\n" +
|
||||
"similarity index 98%\n" +
|
||||
"rename from src/test-bar.js\n" +
|
||||
"rename to src/test-baz.js\n" +
|
||||
"index e01513b..f14a870 100644\n" +
|
||||
"--- a/src/test-bar.js\n" +
|
||||
"+++ b/src/test-baz.js\n" +
|
||||
"@@ -1,4 +1,32 @@\n" +
|
||||
" function foo() {\n" +
|
||||
'diff --git a/src/test-bar.js b/src/test-baz.js\n' +
|
||||
'similarity index 98%\n' +
|
||||
'rename from src/test-bar.js\n' +
|
||||
'rename to src/test-baz.js\n' +
|
||||
'index e01513b..f14a870 100644\n' +
|
||||
'--- a/src/test-bar.js\n' +
|
||||
'+++ b/src/test-baz.js\n' +
|
||||
'@@ -1,4 +1,32 @@\n' +
|
||||
' function foo() {\n' +
|
||||
'-var bar = "Whoops!";\n' +
|
||||
'+var baz = "Whoops!";\n' +
|
||||
" }\n" +
|
||||
" ";
|
||||
' }\n' +
|
||||
' ';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1612,49 +1612,49 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse diff with prefix 2", () => {
|
||||
it('should parse diff with prefix 2', () => {
|
||||
const diff =
|
||||
'diff --git "\tTest.scala" "\tScalaTest.scala"\n' +
|
||||
"similarity index 88%\n" +
|
||||
"rename from Test.scala\n" +
|
||||
"rename to ScalaTest.scala\n" +
|
||||
"index 7d1f9bf..8b13271 100644\n" +
|
||||
'similarity index 88%\n' +
|
||||
'rename from Test.scala\n' +
|
||||
'rename to ScalaTest.scala\n' +
|
||||
'index 7d1f9bf..8b13271 100644\n' +
|
||||
'--- "\tTest.scala"\n' +
|
||||
'+++ "\tScalaTest.scala"\n' +
|
||||
"@@ -1,6 +1,8 @@\n" +
|
||||
" class Test {\n" +
|
||||
" \n" +
|
||||
" def method1 = ???\n" +
|
||||
"+\n" +
|
||||
"+ def method2 = ???\n" +
|
||||
" \n" +
|
||||
" def myMethod = ???\n" +
|
||||
" \n" +
|
||||
"@@ -10,7 +12,6 @@ class Test {\n" +
|
||||
" \n" +
|
||||
" def + = ???\n" +
|
||||
" \n" +
|
||||
"- def |> = ???\n" +
|
||||
" \n" +
|
||||
" }\n" +
|
||||
" \n" +
|
||||
'@@ -1,6 +1,8 @@\n' +
|
||||
' class Test {\n' +
|
||||
' \n' +
|
||||
' def method1 = ???\n' +
|
||||
'+\n' +
|
||||
'+ def method2 = ???\n' +
|
||||
' \n' +
|
||||
' def myMethod = ???\n' +
|
||||
' \n' +
|
||||
'@@ -10,7 +12,6 @@ class Test {\n' +
|
||||
' \n' +
|
||||
' def + = ???\n' +
|
||||
' \n' +
|
||||
'- def |> = ???\n' +
|
||||
' \n' +
|
||||
' }\n' +
|
||||
' \n' +
|
||||
'diff --git "\ttardis.png" "\ttardis.png"\n' +
|
||||
"new file mode 100644\n" +
|
||||
"index 0000000..d503a29\n" +
|
||||
'new file mode 100644\n' +
|
||||
'index 0000000..d503a29\n' +
|
||||
'Binary files /dev/null and "\ttardis.png" differ\n' +
|
||||
"diff --git a/src/test-bar.js b/src/test-baz.js\n" +
|
||||
"similarity index 98%\n" +
|
||||
"rename from src/test-bar.js\n" +
|
||||
"rename to src/test-baz.js\n" +
|
||||
"index e01513b..f14a870 100644\n" +
|
||||
"--- a/src/test-bar.js\n" +
|
||||
"+++ b/src/test-baz.js\n" +
|
||||
"@@ -1,4 +1,32 @@\n" +
|
||||
" function foo() {\n" +
|
||||
'diff --git a/src/test-bar.js b/src/test-baz.js\n' +
|
||||
'similarity index 98%\n' +
|
||||
'rename from src/test-bar.js\n' +
|
||||
'rename to src/test-baz.js\n' +
|
||||
'index e01513b..f14a870 100644\n' +
|
||||
'--- a/src/test-bar.js\n' +
|
||||
'+++ b/src/test-baz.js\n' +
|
||||
'@@ -1,4 +1,32 @@\n' +
|
||||
' function foo() {\n' +
|
||||
'-var bar = "Whoops!";\n' +
|
||||
'+var baz = "Whoops!";\n' +
|
||||
" }\n" +
|
||||
" ";
|
||||
' }\n' +
|
||||
' ';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -1860,39 +1860,39 @@ describe("DiffParser", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should parse binary with content", () => {
|
||||
it('should parse binary with content', () => {
|
||||
const diff =
|
||||
"diff --git a/favicon.png b/favicon.png\n" +
|
||||
"deleted file mode 100644\n" +
|
||||
"index 2a9d516a5647205d7be510dd0dff93a3663eff6f..0000000000000000000000000000000000000000\n" +
|
||||
"GIT binary patch\n" +
|
||||
"literal 0\n" +
|
||||
"HcmV?d00001\n" +
|
||||
"\n" +
|
||||
"literal 471\n" +
|
||||
"zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf<Z~8yL>4nJ\n" +
|
||||
"za0`Jj<E6WGe}IBwC9V-A&PAz-C7Jno3L%-fsSJk3`UaNzMkcGzh!g=;$beJ?=ckpF\n" +
|
||||
"zCl;kLIHu$$r7E~(7NwTw7iAYKI0u`(*t4mJfq_xq)5S5wqIc=!hrWj$cv|<b{x!c(\n" +
|
||||
"z;3r#y;31Y&=1q>qPVOAS4ANVKzqmCp=Cty@U^(7zk!jHsvT~YI{F^=Ex6g|gox78w\n" +
|
||||
"z+Sn2Du3GS9U7qU`1*NYYlJi3u-!<?H-eky}wyIIL;8VU@wCDrb0``&v(jQ*DWSR4K\n" +
|
||||
"zPq(3;isEyho{emNa=%%!jDPE`l3u;5d=q=<+v8kO-=C`*G#t-*AiE-D>-_B#8k9H0\n" +
|
||||
"zGl{FnZs<2$wz5^=Q2h-1XI^s{LQL1#T4epqNPC%Orl(tD_@!*EY++~^Lt2<2&!&%=\n" +
|
||||
"z`m>(TYj6uS7jDdt=eH>iOyQg(QMR<-Fw8)Dk^ZG)XQTuzEgl{`GpS?Cfq9818R9~=\n" +
|
||||
"z{&h9@9n8F^?|qusoPy{k#%tVHzu7H$t26CR`BJZk*Ixf&u36WuS=?6m2^ho-p00i_\n" +
|
||||
"I>zopr0Nz-&lmGw#\n" +
|
||||
"diff --git a/src/test-bar.js b/src/test-baz.js\n" +
|
||||
"similarity index 98%\n" +
|
||||
"rename from src/test-bar.js\n" +
|
||||
"rename to src/test-baz.js\n" +
|
||||
"index e01513b..f14a870 100644\n" +
|
||||
"--- a/src/test-bar.js\n" +
|
||||
"+++ b/src/test-baz.js\n" +
|
||||
"@@ -1,4 +1,32 @@\n" +
|
||||
" function foo() {\n" +
|
||||
'diff --git a/favicon.png b/favicon.png\n' +
|
||||
'deleted file mode 100644\n' +
|
||||
'index 2a9d516a5647205d7be510dd0dff93a3663eff6f..0000000000000000000000000000000000000000\n' +
|
||||
'GIT binary patch\n' +
|
||||
'literal 0\n' +
|
||||
'HcmV?d00001\n' +
|
||||
'\n' +
|
||||
'literal 471\n' +
|
||||
'zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61|;P_|4#%`EX7WqAsj$Z!;#Vf<Z~8yL>4nJ\n' +
|
||||
'za0`Jj<E6WGe}IBwC9V-A&PAz-C7Jno3L%-fsSJk3`UaNzMkcGzh!g=;$beJ?=ckpF\n' +
|
||||
'zCl;kLIHu$$r7E~(7NwTw7iAYKI0u`(*t4mJfq_xq)5S5wqIc=!hrWj$cv|<b{x!c(\n' +
|
||||
'z;3r#y;31Y&=1q>qPVOAS4ANVKzqmCp=Cty@U^(7zk!jHsvT~YI{F^=Ex6g|gox78w\n' +
|
||||
'z+Sn2Du3GS9U7qU`1*NYYlJi3u-!<?H-eky}wyIIL;8VU@wCDrb0``&v(jQ*DWSR4K\n' +
|
||||
'zPq(3;isEyho{emNa=%%!jDPE`l3u;5d=q=<+v8kO-=C`*G#t-*AiE-D>-_B#8k9H0\n' +
|
||||
'zGl{FnZs<2$wz5^=Q2h-1XI^s{LQL1#T4epqNPC%Orl(tD_@!*EY++~^Lt2<2&!&%=\n' +
|
||||
'z`m>(TYj6uS7jDdt=eH>iOyQg(QMR<-Fw8)Dk^ZG)XQTuzEgl{`GpS?Cfq9818R9~=\n' +
|
||||
'z{&h9@9n8F^?|qusoPy{k#%tVHzu7H$t26CR`BJZk*Ixf&u36WuS=?6m2^ho-p00i_\n' +
|
||||
'I>zopr0Nz-&lmGw#\n' +
|
||||
'diff --git a/src/test-bar.js b/src/test-baz.js\n' +
|
||||
'similarity index 98%\n' +
|
||||
'rename from src/test-bar.js\n' +
|
||||
'rename to src/test-baz.js\n' +
|
||||
'index e01513b..f14a870 100644\n' +
|
||||
'--- a/src/test-bar.js\n' +
|
||||
'+++ b/src/test-baz.js\n' +
|
||||
'@@ -1,4 +1,32 @@\n' +
|
||||
' function foo() {\n' +
|
||||
'-var bar = "Whoops!";\n' +
|
||||
'+var baz = "Whoops!";\n' +
|
||||
" }\n" +
|
||||
" ";
|
||||
' }\n' +
|
||||
' ';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { parse, html } from "../diff2html";
|
||||
import { DiffFile, LineType, OutputFormatType } from "../types";
|
||||
import { parse, html } from '../diff2html';
|
||||
import { DiffFile, LineType, OutputFormatType } from '../types';
|
||||
|
||||
const diffExample1 =
|
||||
"diff --git a/sample b/sample\n" +
|
||||
"index 0000001..0ddf2ba\n" +
|
||||
"--- a/sample\n" +
|
||||
"+++ b/sample\n" +
|
||||
"@@ -1 +1 @@\n" +
|
||||
"-test\n" +
|
||||
"+test1\n";
|
||||
'diff --git a/sample b/sample\n' +
|
||||
'index 0000001..0ddf2ba\n' +
|
||||
'--- a/sample\n' +
|
||||
'+++ b/sample\n' +
|
||||
'@@ -1 +1 @@\n' +
|
||||
'-test\n' +
|
||||
'+test1\n';
|
||||
|
||||
const jsonExample1: DiffFile[] = [
|
||||
{
|
||||
|
|
@ -16,47 +16,47 @@ const jsonExample1: DiffFile[] = [
|
|||
{
|
||||
lines: [
|
||||
{
|
||||
content: "-test",
|
||||
content: '-test',
|
||||
type: LineType.DELETE,
|
||||
oldNumber: 1,
|
||||
newNumber: undefined
|
||||
newNumber: undefined,
|
||||
},
|
||||
{
|
||||
content: "+test1",
|
||||
content: '+test1',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 1
|
||||
}
|
||||
newNumber: 1,
|
||||
},
|
||||
],
|
||||
oldStartLine: 1,
|
||||
oldStartLine2: undefined,
|
||||
newStartLine: 1,
|
||||
header: "@@ -1 +1 @@"
|
||||
}
|
||||
header: '@@ -1 +1 @@',
|
||||
},
|
||||
],
|
||||
deletedLines: 1,
|
||||
addedLines: 1,
|
||||
checksumBefore: "0000001",
|
||||
checksumAfter: "0ddf2ba",
|
||||
oldName: "sample",
|
||||
newName: "sample",
|
||||
language: "",
|
||||
checksumBefore: '0000001',
|
||||
checksumAfter: '0ddf2ba',
|
||||
oldName: 'sample',
|
||||
newName: 'sample',
|
||||
language: '',
|
||||
isCombined: false,
|
||||
isGitDiff: true
|
||||
}
|
||||
isGitDiff: true,
|
||||
},
|
||||
];
|
||||
|
||||
describe("Diff2Html", () => {
|
||||
describe("getJsonFromDiff", () => {
|
||||
it("should parse simple diff to json", () => {
|
||||
describe('Diff2Html', () => {
|
||||
describe('getJsonFromDiff', () => {
|
||||
it('should parse simple diff to json', () => {
|
||||
const diff =
|
||||
"diff --git a/sample b/sample\n" +
|
||||
"index 0000001..0ddf2ba\n" +
|
||||
"--- a/sample\n" +
|
||||
"+++ b/sample\n" +
|
||||
"@@ -1 +1 @@\n" +
|
||||
"-test\n" +
|
||||
"+test1\n";
|
||||
'diff --git a/sample b/sample\n' +
|
||||
'index 0000001..0ddf2ba\n' +
|
||||
'--- a/sample\n' +
|
||||
'+++ b/sample\n' +
|
||||
'@@ -1 +1 @@\n' +
|
||||
'-test\n' +
|
||||
'+test1\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -98,23 +98,23 @@ describe("Diff2Html", () => {
|
|||
});
|
||||
|
||||
// Test case for issue #49
|
||||
it("should parse diff with added EOF", () => {
|
||||
it('should parse diff with added EOF', () => {
|
||||
const diff =
|
||||
"diff --git a/sample.scala b/sample.scala\n" +
|
||||
"index b583263..8b2fc3e 100644\n" +
|
||||
"--- a/b583263..8b2fc3e\n" +
|
||||
"+++ b/8b2fc3e\n" +
|
||||
"@@ -50,5 +50,7 @@ case class Response[+A](value: Option[A],\n" +
|
||||
" object ResponseErrorCode extends JsonEnumeration {\n" +
|
||||
" val NoError, ServiceError, JsonError,\n" +
|
||||
" InvalidPermissions, MissingPermissions, GenericError,\n" +
|
||||
"- TokenRevoked, MissingToken = Value\n" +
|
||||
"-}\n" +
|
||||
"\\ No newline at end of file\n" +
|
||||
"+ TokenRevoked, MissingToken,\n" +
|
||||
"+ IndexLock, RepositoryError, NotValidRepo, PullRequestNotMergeable, BranchError,\n" +
|
||||
"+ PluginError, CodeParserError, EngineError = Value\n" +
|
||||
"+}\n";
|
||||
'diff --git a/sample.scala b/sample.scala\n' +
|
||||
'index b583263..8b2fc3e 100644\n' +
|
||||
'--- a/b583263..8b2fc3e\n' +
|
||||
'+++ b/8b2fc3e\n' +
|
||||
'@@ -50,5 +50,7 @@ case class Response[+A](value: Option[A],\n' +
|
||||
' object ResponseErrorCode extends JsonEnumeration {\n' +
|
||||
' val NoError, ServiceError, JsonError,\n' +
|
||||
' InvalidPermissions, MissingPermissions, GenericError,\n' +
|
||||
'- TokenRevoked, MissingToken = Value\n' +
|
||||
'-}\n' +
|
||||
'\\ No newline at end of file\n' +
|
||||
'+ TokenRevoked, MissingToken,\n' +
|
||||
'+ IndexLock, RepositoryError, NotValidRepo, PullRequestNotMergeable, BranchError,\n' +
|
||||
'+ PluginError, CodeParserError, EngineError = Value\n' +
|
||||
'+}\n';
|
||||
const result = parse(diff);
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
Array [
|
||||
|
|
@ -198,7 +198,7 @@ describe("Diff2Html", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should generate pretty line by line html from diff", () => {
|
||||
it('should generate pretty line by line html from diff', () => {
|
||||
const result = html(diffExample1, { drawFileList: false });
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<div class=\\"d2h-wrapper\\">
|
||||
|
|
@ -251,7 +251,7 @@ describe("Diff2Html", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should generate pretty line by line html from json", () => {
|
||||
it('should generate pretty line by line html from json', () => {
|
||||
const result = html(jsonExample1, { drawFileList: false });
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<div class=\\"d2h-wrapper\\">
|
||||
|
|
@ -304,7 +304,7 @@ describe("Diff2Html", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should generate pretty diff with files summary", () => {
|
||||
it('should generate pretty diff with files summary', () => {
|
||||
const result = html(diffExample1, { drawFileList: true });
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<div class=\\"d2h-file-list-wrapper\\">
|
||||
|
|
@ -377,7 +377,7 @@ describe("Diff2Html", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should generate pretty side by side html from diff", () => {
|
||||
it('should generate pretty side by side html from diff', () => {
|
||||
const result = html(diffExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: false });
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<div class=\\"d2h-wrapper\\">
|
||||
|
|
@ -444,7 +444,7 @@ describe("Diff2Html", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should generate pretty side by side html from json", () => {
|
||||
it('should generate pretty side by side html from json', () => {
|
||||
const result = html(jsonExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: false });
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<div class=\\"d2h-wrapper\\">
|
||||
|
|
@ -511,7 +511,7 @@ describe("Diff2Html", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should generate pretty side by side html from diff 2", () => {
|
||||
it('should generate pretty side by side html from diff 2', () => {
|
||||
const result = html(diffExample1, { outputFormat: OutputFormatType.SIDE_BY_SIDE, drawFileList: true });
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<div class=\\"d2h-file-list-wrapper\\">
|
||||
|
|
@ -598,30 +598,30 @@ describe("Diff2Html", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should generate pretty side by side html from diff with html on headers", () => {
|
||||
it('should generate pretty side by side html from diff with html on headers', () => {
|
||||
const diffExample2 =
|
||||
"diff --git a/CHANGELOG.md b/CHANGELOG.md\n" +
|
||||
"index fc3e3f4..b486d10 100644\n" +
|
||||
"--- a/CHANGELOG.md\n" +
|
||||
"+++ b/CHANGELOG.md\n" +
|
||||
"@@ -1,7 +1,6 @@\n" +
|
||||
" # Change Log\n" +
|
||||
" All notable changes to this project will be documented in this file.\n" +
|
||||
" This project adheres to [Semantic Versioning](http://semver.org/).\n" +
|
||||
'diff --git a/CHANGELOG.md b/CHANGELOG.md\n' +
|
||||
'index fc3e3f4..b486d10 100644\n' +
|
||||
'--- a/CHANGELOG.md\n' +
|
||||
'+++ b/CHANGELOG.md\n' +
|
||||
'@@ -1,7 +1,6 @@\n' +
|
||||
' # Change Log\n' +
|
||||
' All notable changes to this project will be documented in this file.\n' +
|
||||
' This project adheres to [Semantic Versioning](http://semver.org/).\n' +
|
||||
'-$a="<table><tr><td>Use the following format for additions: ` - VERSION: [feature/patch (if applicable)] Short description of change. Links to relevant issues/PRs.`\n' +
|
||||
' $a="<table><tr><td>\n' +
|
||||
" $a=\"<table><tr><td>- 1.1.9: Fix around ubuntu's inability to cache promises. [#877](https://github.com/FredrikNoren/ungit/pull/878)\n" +
|
||||
" - 1.1.8:\n" +
|
||||
"@@ -11,7 +10,7 @@ $a="<table><tr><td>- 1.1.9: Fix around ubuntu's inability to cache promises. [#8\n" +
|
||||
" - 1.1.7:\n" +
|
||||
" - Fix diff flickering issue and optimization [#865](https://github.com/FredrikNoren/ungit/pull/865)\n" +
|
||||
" - Fix credential dialog issue [#864](https://github.com/FredrikNoren/ungit/pull/864)\n" +
|
||||
"- - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n" +
|
||||
"+4 - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n" +
|
||||
" - 1.1.6: Fix path auto complete [#861](https://github.com/FredrikNoren/ungit/issues/861)\n" +
|
||||
' $a="<table><tr><td>- 1.1.9: Fix around ubuntu\'s inability to cache promises. [#877](https://github.com/FredrikNoren/ungit/pull/878)\n' +
|
||||
' - 1.1.8:\n' +
|
||||
'@@ -11,7 +10,7 @@ $a="<table><tr><td>- 1.1.9: Fix around ubuntu's inability to cache promises. [#8\n' +
|
||||
' - 1.1.7:\n' +
|
||||
' - Fix diff flickering issue and optimization [#865](https://github.com/FredrikNoren/ungit/pull/865)\n' +
|
||||
' - Fix credential dialog issue [#864](https://github.com/FredrikNoren/ungit/pull/864)\n' +
|
||||
'- - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n' +
|
||||
'+4 - Fix HEAD branch order when redraw [#858](https://github.com/FredrikNoren/ungit/issues/858)\n' +
|
||||
' - 1.1.6: Fix path auto complete [#861](https://github.com/FredrikNoren/ungit/issues/861)\n' +
|
||||
' - 1.1.5: Update "Toggle all" button after commit or changing selected files [#859](https://github.com/FredrikNoren/ungit/issues/859)\n' +
|
||||
" - 1.1.4: [patch] Promise refactoring\n" +
|
||||
" \n";
|
||||
' - 1.1.4: [patch] Promise refactoring\n' +
|
||||
' \n';
|
||||
const result = html(diffExample2, { drawFileList: false });
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<div class=\\"d2h-wrapper\\">
|
||||
|
|
|
|||
|
|
@ -1,14 +1,14 @@
|
|||
import { render } from "../file-list-renderer";
|
||||
import HoganJsUtils from "../hoganjs-utils";
|
||||
import { render } from '../file-list-renderer';
|
||||
import HoganJsUtils from '../hoganjs-utils';
|
||||
|
||||
describe("FileListPrinter", () => {
|
||||
describe("generateFileList", () => {
|
||||
it("should expose old and new files to templates", () => {
|
||||
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}}"
|
||||
}
|
||||
'file-summary-wrapper': '{{{files}}}',
|
||||
'file-summary-line': '{{oldName}}, {{newName}}, {{fileName}}',
|
||||
},
|
||||
});
|
||||
const files = [
|
||||
{
|
||||
|
|
@ -17,9 +17,9 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 12,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name.js",
|
||||
newName: "my/file/name.js"
|
||||
language: 'js',
|
||||
oldName: 'my/file/name.js',
|
||||
newName: 'my/file/name.js',
|
||||
},
|
||||
{
|
||||
isCombined: false,
|
||||
|
|
@ -27,9 +27,9 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 12,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name1.js",
|
||||
newName: "my/file/name2.js"
|
||||
language: 'js',
|
||||
oldName: 'my/file/name1.js',
|
||||
newName: 'my/file/name2.js',
|
||||
},
|
||||
{
|
||||
isCombined: false,
|
||||
|
|
@ -37,10 +37,10 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 12,
|
||||
deletedLines: 0,
|
||||
language: "js",
|
||||
oldName: "dev/null",
|
||||
newName: "my/file/name.js",
|
||||
isNew: true
|
||||
language: 'js',
|
||||
oldName: 'dev/null',
|
||||
newName: 'my/file/name.js',
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
isCombined: false,
|
||||
|
|
@ -48,11 +48,11 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 0,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name.js",
|
||||
newName: "dev/null",
|
||||
isDeleted: true
|
||||
}
|
||||
language: 'js',
|
||||
oldName: 'my/file/name.js',
|
||||
newName: 'dev/null',
|
||||
isDeleted: true,
|
||||
},
|
||||
];
|
||||
|
||||
const fileHtml = render(files, hoganUtils);
|
||||
|
|
@ -65,7 +65,7 @@ describe("FileListPrinter", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should work for all kinds of files", () => {
|
||||
it('should work for all kinds of files', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const files = [
|
||||
{
|
||||
|
|
@ -74,9 +74,9 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 12,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name.js",
|
||||
newName: "my/file/name.js"
|
||||
language: 'js',
|
||||
oldName: 'my/file/name.js',
|
||||
newName: 'my/file/name.js',
|
||||
},
|
||||
{
|
||||
isCombined: false,
|
||||
|
|
@ -84,9 +84,9 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 12,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name1.js",
|
||||
newName: "my/file/name2.js"
|
||||
language: 'js',
|
||||
oldName: 'my/file/name1.js',
|
||||
newName: 'my/file/name2.js',
|
||||
},
|
||||
{
|
||||
isCombined: false,
|
||||
|
|
@ -94,10 +94,10 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 12,
|
||||
deletedLines: 0,
|
||||
language: "js",
|
||||
oldName: "dev/null",
|
||||
newName: "my/file/name.js",
|
||||
isNew: true
|
||||
language: 'js',
|
||||
oldName: 'dev/null',
|
||||
newName: 'my/file/name.js',
|
||||
isNew: true,
|
||||
},
|
||||
{
|
||||
isCombined: false,
|
||||
|
|
@ -105,11 +105,11 @@ describe("FileListPrinter", () => {
|
|||
blocks: [],
|
||||
addedLines: 0,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name.js",
|
||||
newName: "dev/null",
|
||||
isDeleted: true
|
||||
}
|
||||
language: 'js',
|
||||
oldName: 'my/file/name.js',
|
||||
newName: 'dev/null',
|
||||
isDeleted: true,
|
||||
},
|
||||
];
|
||||
const fileHtml = render(files, hoganUtils);
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
|
|
|
|||
|
|
@ -1,13 +1,13 @@
|
|||
import HoganJsUtils from "../hoganjs-utils";
|
||||
import { CSSLineClass } from "../render-utils";
|
||||
import HoganJsUtils from '../hoganjs-utils';
|
||||
import { CSSLineClass } from '../render-utils';
|
||||
|
||||
describe("HoganJsUtils", () => {
|
||||
describe("render", () => {
|
||||
it("should render view", () => {
|
||||
describe('HoganJsUtils', () => {
|
||||
describe('render', () => {
|
||||
it('should render view', () => {
|
||||
const hoganJsUtils = new HoganJsUtils({});
|
||||
const result = hoganJsUtils.render("generic", "empty-diff", {
|
||||
contentClass: "d2h-code-line",
|
||||
CSSLineClass: CSSLineClass
|
||||
const result = hoganJsUtils.render('generic', 'empty-diff', {
|
||||
contentClass: 'd2h-code-line',
|
||||
CSSLineClass: CSSLineClass,
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<tr>
|
||||
|
|
@ -20,53 +20,36 @@ describe("HoganJsUtils", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should render view without cache", () => {
|
||||
it('should throw exception if template is missing', () => {
|
||||
const hoganJsUtils = new HoganJsUtils({});
|
||||
const result = hoganJsUtils.render("generic", "empty-diff", {
|
||||
contentClass: "d2h-code-line",
|
||||
CSSLineClass: CSSLineClass
|
||||
});
|
||||
expect(result).toMatchInlineSnapshot(`
|
||||
"<tr>
|
||||
<td class=\\"d2h-info\\">
|
||||
<div class=\\"d2h-code-line d2h-info\\">
|
||||
File without changes
|
||||
</div>
|
||||
</td>
|
||||
</tr>"
|
||||
`);
|
||||
expect(() => hoganJsUtils.render('generic', 'missing-template', {})).toThrow(Error);
|
||||
});
|
||||
|
||||
it("should throw exception if template is missing", () => {
|
||||
const hoganJsUtils = new HoganJsUtils({});
|
||||
expect(() => hoganJsUtils.render("generic", "missing-template", {})).toThrow(Error);
|
||||
});
|
||||
it('should allow templates to be overridden with compiled templates', () => {
|
||||
const emptyDiffTemplate = HoganJsUtils.compile('<p>{{myName}}</p>');
|
||||
const hoganJsUtils = new HoganJsUtils({ compiledTemplates: { 'generic-empty-diff': emptyDiffTemplate } });
|
||||
|
||||
it("should allow templates to be overridden with compiled templates", () => {
|
||||
const emptyDiffTemplate = HoganJsUtils.compile("<p>{{myName}}</p>");
|
||||
const hoganJsUtils = new HoganJsUtils({ compiledTemplates: { "generic-empty-diff": emptyDiffTemplate } });
|
||||
|
||||
const result = hoganJsUtils.render("generic", "empty-diff", { myName: "Rodrigo Fernandes" });
|
||||
const result = hoganJsUtils.render('generic', 'empty-diff', { myName: 'Rodrigo Fernandes' });
|
||||
expect(result).toMatchInlineSnapshot(`"<p>Rodrigo Fernandes</p>"`);
|
||||
});
|
||||
|
||||
it("should allow templates to be overridden with uncompiled templates", () => {
|
||||
const emptyDiffTemplate = "<p>{{myName}}</p>";
|
||||
const hoganJsUtils = new HoganJsUtils({ rawTemplates: { "generic-empty-diff": emptyDiffTemplate } });
|
||||
it('should allow templates to be overridden with uncompiled templates', () => {
|
||||
const emptyDiffTemplate = '<p>{{myName}}</p>';
|
||||
const hoganJsUtils = new HoganJsUtils({ rawTemplates: { 'generic-empty-diff': emptyDiffTemplate } });
|
||||
|
||||
const result = hoganJsUtils.render("generic", "empty-diff", { myName: "Rodrigo Fernandes" });
|
||||
const result = hoganJsUtils.render('generic', 'empty-diff', { myName: 'Rodrigo Fernandes' });
|
||||
expect(result).toMatchInlineSnapshot(`"<p>Rodrigo Fernandes</p>"`);
|
||||
});
|
||||
|
||||
it("should allow templates to be overridden giving priority to raw templates", () => {
|
||||
const emptyDiffTemplate = HoganJsUtils.compile("<p>Not used!</p>");
|
||||
const emptyDiffTemplateUncompiled = "<p>{{myName}}</p>";
|
||||
it('should allow templates to be overridden giving priority to raw templates', () => {
|
||||
const emptyDiffTemplate = HoganJsUtils.compile('<p>Not used!</p>');
|
||||
const emptyDiffTemplateUncompiled = '<p>{{myName}}</p>';
|
||||
const hoganJsUtils = new HoganJsUtils({
|
||||
compiledTemplates: { "generic-empty-diff": emptyDiffTemplate },
|
||||
rawTemplates: { "generic-empty-diff": emptyDiffTemplateUncompiled }
|
||||
compiledTemplates: { 'generic-empty-diff': emptyDiffTemplate },
|
||||
rawTemplates: { 'generic-empty-diff': emptyDiffTemplateUncompiled },
|
||||
});
|
||||
|
||||
const result = hoganJsUtils.render("generic", "empty-diff", { myName: "Rodrigo Fernandes" });
|
||||
const result = hoganJsUtils.render('generic', 'empty-diff', { myName: 'Rodrigo Fernandes' });
|
||||
expect(result).toMatchInlineSnapshot(`"<p>Rodrigo Fernandes</p>"`);
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import LineByLineRenderer from "../line-by-line-renderer";
|
||||
import HoganJsUtils from "../hoganjs-utils";
|
||||
import { LineType, DiffFile, LineMatchingType } from "../types";
|
||||
import { CSSLineClass } from "../render-utils";
|
||||
import LineByLineRenderer from '../line-by-line-renderer';
|
||||
import HoganJsUtils from '../hoganjs-utils';
|
||||
import { LineType, DiffFile, LineMatchingType } from '../types';
|
||||
import { CSSLineClass } from '../render-utils';
|
||||
|
||||
describe("LineByLineRenderer", () => {
|
||||
describe("_generateEmptyDiff", () => {
|
||||
it("should return an empty diff", () => {
|
||||
describe('LineByLineRenderer', () => {
|
||||
describe('_generateEmptyDiff', () => {
|
||||
it('should return an empty diff', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
const fileHtml = lineByLineRenderer.generateEmptyDiff();
|
||||
|
|
@ -21,16 +21,16 @@ describe("LineByLineRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("makeLineHtml", () => {
|
||||
it("should work for insertions", () => {
|
||||
describe('makeLineHtml', () => {
|
||||
it('should work for insertions', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
|
||||
type: CSSLineClass.INSERTS,
|
||||
prefix: "+",
|
||||
content: "test",
|
||||
prefix: '+',
|
||||
content: 'test',
|
||||
oldNumber: undefined,
|
||||
newNumber: 30
|
||||
newNumber: 30,
|
||||
});
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
"<tr>
|
||||
|
|
@ -48,15 +48,15 @@ describe("LineByLineRenderer", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should work for deletions", () => {
|
||||
it('should work for deletions', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
|
||||
type: CSSLineClass.DELETES,
|
||||
prefix: "-",
|
||||
content: "test",
|
||||
prefix: '-',
|
||||
content: 'test',
|
||||
oldNumber: 30,
|
||||
newNumber: undefined
|
||||
newNumber: undefined,
|
||||
});
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
"<tr>
|
||||
|
|
@ -74,15 +74,15 @@ describe("LineByLineRenderer", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should convert indents into non breakin spaces (2 white spaces)", () => {
|
||||
it('should convert indents into non breakin spaces (2 white spaces)', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
|
||||
type: CSSLineClass.INSERTS,
|
||||
prefix: "+",
|
||||
content: " test",
|
||||
prefix: '+',
|
||||
content: ' test',
|
||||
oldNumber: undefined,
|
||||
newNumber: 30
|
||||
newNumber: 30,
|
||||
});
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
"<tr>
|
||||
|
|
@ -100,15 +100,15 @@ describe("LineByLineRenderer", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should convert indents into non breakin spaces (4 white spaces)", () => {
|
||||
it('should convert indents into non breakin spaces (4 white spaces)', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
|
||||
type: CSSLineClass.INSERTS,
|
||||
prefix: "+",
|
||||
content: " test",
|
||||
prefix: '+',
|
||||
content: ' test',
|
||||
oldNumber: undefined,
|
||||
newNumber: 30
|
||||
newNumber: 30,
|
||||
});
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
"<tr>
|
||||
|
|
@ -126,15 +126,15 @@ describe("LineByLineRenderer", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should preserve tabs", () => {
|
||||
it('should preserve tabs', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
const fileHtml = lineByLineRenderer.generateSingleLineHtml({
|
||||
type: CSSLineClass.INSERTS,
|
||||
prefix: "+",
|
||||
content: "\ttest",
|
||||
prefix: '+',
|
||||
content: '\ttest',
|
||||
oldNumber: undefined,
|
||||
newNumber: 30
|
||||
newNumber: 30,
|
||||
});
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
"<tr>
|
||||
|
|
@ -153,22 +153,22 @@ describe("LineByLineRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("makeFileDiffHtml", () => {
|
||||
it("should work for simple file", () => {
|
||||
describe('makeFileDiffHtml', () => {
|
||||
it('should work for simple file', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
|
||||
const file = {
|
||||
addedLines: 12,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name.js",
|
||||
newName: "my/file/name.js",
|
||||
language: 'js',
|
||||
oldName: 'my/file/name.js',
|
||||
newName: 'my/file/name.js',
|
||||
isCombined: false,
|
||||
isGitDiff: false,
|
||||
blocks: []
|
||||
blocks: [],
|
||||
};
|
||||
const diffs = "<span>Random Html</span>";
|
||||
const diffs = '<span>Random Html</span>';
|
||||
|
||||
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
|
||||
|
||||
|
|
@ -193,22 +193,22 @@ describe("LineByLineRenderer", () => {
|
|||
</div>"
|
||||
`);
|
||||
});
|
||||
it("should work for simple added file", () => {
|
||||
it('should work for simple added file', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
|
||||
const file = {
|
||||
addedLines: 12,
|
||||
deletedLines: 0,
|
||||
language: "js",
|
||||
oldName: "dev/null",
|
||||
newName: "my/file/name.js",
|
||||
language: 'js',
|
||||
oldName: 'dev/null',
|
||||
newName: 'my/file/name.js',
|
||||
isNew: true,
|
||||
isCombined: false,
|
||||
isGitDiff: false,
|
||||
blocks: []
|
||||
blocks: [],
|
||||
};
|
||||
const diffs = "<span>Random Html</span>";
|
||||
const diffs = '<span>Random Html</span>';
|
||||
|
||||
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
|
||||
|
||||
|
|
@ -233,22 +233,22 @@ describe("LineByLineRenderer", () => {
|
|||
</div>"
|
||||
`);
|
||||
});
|
||||
it("should work for simple deleted file", () => {
|
||||
it('should work for simple deleted file', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
|
||||
const file = {
|
||||
addedLines: 0,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name.js",
|
||||
newName: "dev/null",
|
||||
language: 'js',
|
||||
oldName: 'my/file/name.js',
|
||||
newName: 'dev/null',
|
||||
isDeleted: true,
|
||||
isCombined: false,
|
||||
isGitDiff: false,
|
||||
blocks: []
|
||||
blocks: [],
|
||||
};
|
||||
const diffs = "<span>Random Html</span>";
|
||||
const diffs = '<span>Random Html</span>';
|
||||
|
||||
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
|
||||
|
||||
|
|
@ -273,22 +273,22 @@ describe("LineByLineRenderer", () => {
|
|||
</div>"
|
||||
`);
|
||||
});
|
||||
it("should work for simple renamed file", () => {
|
||||
it('should work for simple renamed file', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
|
||||
const file = {
|
||||
addedLines: 12,
|
||||
deletedLines: 41,
|
||||
language: "js",
|
||||
oldName: "my/file/name1.js",
|
||||
newName: "my/file/name2.js",
|
||||
language: 'js',
|
||||
oldName: 'my/file/name1.js',
|
||||
newName: 'my/file/name2.js',
|
||||
isRename: true,
|
||||
isCombined: false,
|
||||
isGitDiff: false,
|
||||
blocks: []
|
||||
blocks: [],
|
||||
};
|
||||
const diffs = "<span>Random Html</span>";
|
||||
const diffs = '<span>Random Html</span>';
|
||||
|
||||
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
|
||||
|
||||
|
|
@ -313,25 +313,25 @@ describe("LineByLineRenderer", () => {
|
|||
</div>"
|
||||
`);
|
||||
});
|
||||
it("should return empty when option renderNothingWhenEmpty is true and file blocks not present", () => {
|
||||
it('should return empty when option renderNothingWhenEmpty is true and file blocks not present', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {
|
||||
renderNothingWhenEmpty: true
|
||||
renderNothingWhenEmpty: true,
|
||||
});
|
||||
|
||||
const file = {
|
||||
addedLines: 0,
|
||||
deletedLines: 0,
|
||||
language: "js",
|
||||
oldName: "my/file/name1.js",
|
||||
newName: "my/file/name2.js",
|
||||
language: 'js',
|
||||
oldName: 'my/file/name1.js',
|
||||
newName: 'my/file/name2.js',
|
||||
isRename: true,
|
||||
isCombined: false,
|
||||
isGitDiff: false,
|
||||
blocks: []
|
||||
blocks: [],
|
||||
};
|
||||
|
||||
const diffs = "<span>Random Html</span>";
|
||||
const diffs = '<span>Random Html</span>';
|
||||
|
||||
const fileHtml = lineByLineRenderer.makeFileDiffHtml(file, diffs);
|
||||
|
||||
|
|
@ -339,47 +339,47 @@ describe("LineByLineRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("generateLineByLineJsonHtml", () => {
|
||||
it("should work for list of files", () => {
|
||||
describe('generateLineByLineJsonHtml', () => {
|
||||
it('should work for list of files', () => {
|
||||
const exampleJson: DiffFile[] = [
|
||||
{
|
||||
blocks: [
|
||||
{
|
||||
lines: [
|
||||
{
|
||||
content: "-test",
|
||||
content: '-test',
|
||||
type: LineType.DELETE,
|
||||
oldNumber: 1,
|
||||
newNumber: undefined
|
||||
newNumber: undefined,
|
||||
},
|
||||
{
|
||||
content: "+test1r",
|
||||
content: '+test1r',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 1
|
||||
}
|
||||
newNumber: 1,
|
||||
},
|
||||
],
|
||||
oldStartLine: 1,
|
||||
oldStartLine2: undefined,
|
||||
newStartLine: 1,
|
||||
header: "@@ -1 +1 @@"
|
||||
}
|
||||
header: '@@ -1 +1 @@',
|
||||
},
|
||||
],
|
||||
deletedLines: 1,
|
||||
addedLines: 1,
|
||||
checksumBefore: "0000001",
|
||||
checksumAfter: "0ddf2ba",
|
||||
oldName: "sample",
|
||||
newName: "sample",
|
||||
language: "txt",
|
||||
checksumBefore: '0000001',
|
||||
checksumAfter: '0ddf2ba',
|
||||
oldName: 'sample',
|
||||
newName: 'sample',
|
||||
language: 'txt',
|
||||
isCombined: false,
|
||||
isGitDiff: true
|
||||
}
|
||||
isGitDiff: true,
|
||||
},
|
||||
];
|
||||
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {
|
||||
matching: LineMatchingType.LINES
|
||||
matching: LineMatchingType.LINES,
|
||||
});
|
||||
const html = lineByLineRenderer.render(exampleJson);
|
||||
expect(html).toMatchInlineSnapshot(`
|
||||
|
|
@ -433,23 +433,23 @@ describe("LineByLineRenderer", () => {
|
|||
`);
|
||||
});
|
||||
|
||||
it("should work for empty blocks", () => {
|
||||
it('should work for empty blocks', () => {
|
||||
const exampleJson = [
|
||||
{
|
||||
blocks: [],
|
||||
deletedLines: 0,
|
||||
addedLines: 0,
|
||||
oldName: "sample",
|
||||
language: "js",
|
||||
newName: "sample",
|
||||
oldName: 'sample',
|
||||
language: 'js',
|
||||
newName: 'sample',
|
||||
isCombined: false,
|
||||
isGitDiff: false
|
||||
}
|
||||
isGitDiff: false,
|
||||
},
|
||||
];
|
||||
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {
|
||||
renderNothingWhenEmpty: false
|
||||
renderNothingWhenEmpty: false,
|
||||
});
|
||||
const html = lineByLineRenderer.render(exampleJson);
|
||||
expect(html).toMatchInlineSnapshot(`
|
||||
|
|
@ -483,8 +483,8 @@ describe("LineByLineRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("_generateFileHtml", () => {
|
||||
it("should work for simple file", () => {
|
||||
describe('_generateFileHtml', () => {
|
||||
it('should work for simple file', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const lineByLineRenderer = new LineByLineRenderer(hoganUtils, {});
|
||||
const file: DiffFile = {
|
||||
|
|
@ -492,45 +492,45 @@ describe("LineByLineRenderer", () => {
|
|||
{
|
||||
lines: [
|
||||
{
|
||||
content: " one context line",
|
||||
content: ' one context line',
|
||||
type: LineType.CONTEXT,
|
||||
oldNumber: 1,
|
||||
newNumber: 1
|
||||
newNumber: 1,
|
||||
},
|
||||
{
|
||||
content: "-test",
|
||||
content: '-test',
|
||||
type: LineType.DELETE,
|
||||
oldNumber: 2,
|
||||
newNumber: undefined
|
||||
newNumber: undefined,
|
||||
},
|
||||
{
|
||||
content: "+test1r",
|
||||
content: '+test1r',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 2
|
||||
newNumber: 2,
|
||||
},
|
||||
{
|
||||
content: "+test2r",
|
||||
content: '+test2r',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 3
|
||||
}
|
||||
newNumber: 3,
|
||||
},
|
||||
],
|
||||
oldStartLine: 1,
|
||||
oldStartLine2: undefined,
|
||||
newStartLine: 1,
|
||||
header: "@@ -1 +1 @@"
|
||||
}
|
||||
header: '@@ -1 +1 @@',
|
||||
},
|
||||
],
|
||||
deletedLines: 1,
|
||||
addedLines: 1,
|
||||
checksumBefore: "0000001",
|
||||
checksumAfter: "0ddf2ba",
|
||||
oldName: "sample",
|
||||
language: "txt",
|
||||
newName: "sample",
|
||||
checksumBefore: '0000001',
|
||||
checksumAfter: '0ddf2ba',
|
||||
oldName: 'sample',
|
||||
language: 'txt',
|
||||
newName: 'sample',
|
||||
isCombined: false,
|
||||
isGitDiff: true
|
||||
isGitDiff: true,
|
||||
};
|
||||
|
||||
const html = lineByLineRenderer.generateFileHtml(file);
|
||||
|
|
|
|||
|
|
@ -1,158 +1,151 @@
|
|||
import { escapeForHtml, getHtmlId, filenameDiff, diffHighlight } from "../render-utils";
|
||||
import { DiffStyleType, LineMatchingType } from "../types";
|
||||
import { escapeForHtml, getHtmlId, filenameDiff, diffHighlight } from '../render-utils';
|
||||
import { DiffStyleType, LineMatchingType } from '../types';
|
||||
|
||||
describe("Utils", () => {
|
||||
describe("escapeForHtml", () => {
|
||||
it("should escape & with &", () => {
|
||||
const result = escapeForHtml("&");
|
||||
expect(result).toEqual("&");
|
||||
describe('Utils', () => {
|
||||
describe('escapeForHtml', () => {
|
||||
it('should escape & with &', () => {
|
||||
const result = escapeForHtml('&');
|
||||
expect(result).toEqual('&');
|
||||
});
|
||||
it("should escape < with <", () => {
|
||||
const result = escapeForHtml("<");
|
||||
expect(result).toEqual("<");
|
||||
it('should escape < with <', () => {
|
||||
const result = escapeForHtml('<');
|
||||
expect(result).toEqual('<');
|
||||
});
|
||||
it("should escape > with >", () => {
|
||||
const result = escapeForHtml(">");
|
||||
expect(result).toEqual(">");
|
||||
it('should escape > with >', () => {
|
||||
const result = escapeForHtml('>');
|
||||
expect(result).toEqual('>');
|
||||
});
|
||||
it('should escape " with "', () => {
|
||||
const result = escapeForHtml('"');
|
||||
expect(result).toEqual(""");
|
||||
expect(result).toEqual('"');
|
||||
});
|
||||
it("should escape ' with '", () => {
|
||||
const result = escapeForHtml("'");
|
||||
expect(result).toEqual("'");
|
||||
expect(result).toEqual(''');
|
||||
});
|
||||
it("should escape / with /", () => {
|
||||
const result = escapeForHtml("/");
|
||||
expect(result).toEqual("/");
|
||||
it('should escape / with /', () => {
|
||||
const result = escapeForHtml('/');
|
||||
expect(result).toEqual('/');
|
||||
});
|
||||
it("should escape a string containing HTML code", () => {
|
||||
it('should escape a string containing HTML code', () => {
|
||||
const result = escapeForHtml(`<a href="/search?q=diff2html">Search 'Diff2Html'</a>`);
|
||||
expect(result).toEqual(
|
||||
"<a href="/search?q=diff2html">Search 'Diff2Html'</a>"
|
||||
'<a href="/search?q=diff2html">Search 'Diff2Html'</a>',
|
||||
);
|
||||
});
|
||||
});
|
||||
|
||||
describe("getHtmlId", () => {
|
||||
it("should generate file unique id", () => {
|
||||
describe('getHtmlId', () => {
|
||||
it('should generate file unique id', () => {
|
||||
const result = getHtmlId({
|
||||
oldName: "sample.js",
|
||||
newName: "sample.js"
|
||||
oldName: 'sample.js',
|
||||
newName: 'sample.js',
|
||||
});
|
||||
expect(result).toEqual("d2h-960013");
|
||||
});
|
||||
it("should generate file unique id for empty hashes", () => {
|
||||
const result = getHtmlId({
|
||||
oldName: "sample.js",
|
||||
newName: "sample.js"
|
||||
});
|
||||
expect(result).toEqual("d2h-960013");
|
||||
expect(result).toEqual('d2h-960013');
|
||||
});
|
||||
});
|
||||
|
||||
describe("getDiffName", () => {
|
||||
it("should generate the file name for a changed file", () => {
|
||||
describe('getDiffName', () => {
|
||||
it('should generate the file name for a changed file', () => {
|
||||
const result = filenameDiff({
|
||||
oldName: "sample.js",
|
||||
newName: "sample.js"
|
||||
oldName: 'sample.js',
|
||||
newName: 'sample.js',
|
||||
});
|
||||
expect(result).toEqual("sample.js");
|
||||
expect(result).toEqual('sample.js');
|
||||
});
|
||||
it("should generate the file name for a changed file and full rename", () => {
|
||||
it('should generate the file name for a changed file and full rename', () => {
|
||||
const result = filenameDiff({
|
||||
oldName: "sample1.js",
|
||||
newName: "sample2.js"
|
||||
oldName: 'sample1.js',
|
||||
newName: 'sample2.js',
|
||||
});
|
||||
expect(result).toEqual("sample1.js → sample2.js");
|
||||
expect(result).toEqual('sample1.js → sample2.js');
|
||||
});
|
||||
it("should generate the file name for a changed file and prefix rename", () => {
|
||||
it('should generate the file name for a changed file and prefix rename', () => {
|
||||
const result = filenameDiff({
|
||||
oldName: "src/path/sample.js",
|
||||
newName: "source/path/sample.js"
|
||||
oldName: 'src/path/sample.js',
|
||||
newName: 'source/path/sample.js',
|
||||
});
|
||||
expect(result).toEqual("{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", () => {
|
||||
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"
|
||||
oldName: 'src/path/sample1.js',
|
||||
newName: 'src/path/sample2.js',
|
||||
});
|
||||
expect(result).toEqual("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", () => {
|
||||
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"
|
||||
oldName: 'src/really/big/path/sample.js',
|
||||
newName: 'src/small/path/sample.js',
|
||||
});
|
||||
expect(result).toEqual("src/{really/big → small}/path/sample.js");
|
||||
expect(result).toEqual('src/{really/big → small}/path/sample.js');
|
||||
});
|
||||
it("should generate the file name for a deleted file", () => {
|
||||
it('should generate the file name for a deleted file', () => {
|
||||
const result = filenameDiff({
|
||||
oldName: "src/my/file.js",
|
||||
newName: "/dev/null"
|
||||
oldName: 'src/my/file.js',
|
||||
newName: '/dev/null',
|
||||
});
|
||||
expect(result).toEqual("src/my/file.js");
|
||||
expect(result).toEqual('src/my/file.js');
|
||||
});
|
||||
it("should generate the file name for a new file", () => {
|
||||
it('should generate the file name for a new file', () => {
|
||||
const result = filenameDiff({
|
||||
oldName: "/dev/null",
|
||||
newName: "src/my/file.js"
|
||||
oldName: '/dev/null',
|
||||
newName: 'src/my/file.js',
|
||||
});
|
||||
expect(result).toEqual("src/my/file.js");
|
||||
expect(result).toEqual('src/my/file.js');
|
||||
});
|
||||
});
|
||||
|
||||
describe("diffHighlight", () => {
|
||||
it("should highlight two lines", () => {
|
||||
const result = diffHighlight("-var myVar = 2;", "+var myVariable = 3;", false, {
|
||||
matching: LineMatchingType.WORDS
|
||||
describe('diffHighlight', () => {
|
||||
it('should highlight two lines', () => {
|
||||
const result = diffHighlight('-var myVar = 2;', '+var myVariable = 3;', false, {
|
||||
matching: LineMatchingType.WORDS,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
oldLine: {
|
||||
prefix: "-",
|
||||
content: "var <del>myVar</del> = <del>2</del>;"
|
||||
prefix: '-',
|
||||
content: 'var <del>myVar</del> = <del>2</del>;',
|
||||
},
|
||||
newLine: {
|
||||
prefix: "+",
|
||||
content: "var <ins>myVariable</ins> = <ins>3</ins>;"
|
||||
}
|
||||
prefix: '+',
|
||||
content: 'var <ins>myVariable</ins> = <ins>3</ins>;',
|
||||
},
|
||||
});
|
||||
});
|
||||
it("should highlight two lines char by char", () => {
|
||||
const result = diffHighlight("-var myVar = 2;", "+var myVariable = 3;", false, {
|
||||
diffStyle: DiffStyleType.CHAR
|
||||
it('should highlight two lines char by char', () => {
|
||||
const result = diffHighlight('-var myVar = 2;', '+var myVariable = 3;', false, {
|
||||
diffStyle: DiffStyleType.CHAR,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
oldLine: {
|
||||
prefix: "-",
|
||||
content: "var myVar = <del>2</del>;"
|
||||
prefix: '-',
|
||||
content: 'var myVar = <del>2</del>;',
|
||||
},
|
||||
newLine: {
|
||||
prefix: "+",
|
||||
content: "var myVar<ins>iable</ins> = <ins>3</ins>;"
|
||||
}
|
||||
prefix: '+',
|
||||
content: 'var myVar<ins>iable</ins> = <ins>3</ins>;',
|
||||
},
|
||||
});
|
||||
});
|
||||
it("should highlight combined diff lines", () => {
|
||||
const result = diffHighlight(" -var myVar = 2;", " +var myVariable = 3;", true, {
|
||||
it('should highlight combined diff lines', () => {
|
||||
const result = diffHighlight(' -var myVar = 2;', ' +var myVariable = 3;', true, {
|
||||
diffStyle: DiffStyleType.WORD,
|
||||
matching: LineMatchingType.WORDS,
|
||||
matchWordsThreshold: 1.0
|
||||
matchWordsThreshold: 1.0,
|
||||
});
|
||||
|
||||
expect(result).toEqual({
|
||||
oldLine: {
|
||||
prefix: " -",
|
||||
content: 'var <del class="d2h-change">myVar</del> = <del class="d2h-change">2</del>;'
|
||||
prefix: ' -',
|
||||
content: 'var <del class="d2h-change">myVar</del> = <del class="d2h-change">2</del>;',
|
||||
},
|
||||
newLine: {
|
||||
prefix: " +",
|
||||
content: 'var <ins class="d2h-change">myVariable</ins> = <ins class="d2h-change">3</ins>;'
|
||||
}
|
||||
prefix: ' +',
|
||||
content: 'var <ins class="d2h-change">myVariable</ins> = <ins class="d2h-change">3</ins>;',
|
||||
},
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,11 +1,11 @@
|
|||
import SideBySideRenderer from "../side-by-side-renderer";
|
||||
import HoganJsUtils from "../hoganjs-utils";
|
||||
import { LineType, DiffLine, DiffFile, LineMatchingType } from "../types";
|
||||
import { CSSLineClass } from "../render-utils";
|
||||
import SideBySideRenderer from '../side-by-side-renderer';
|
||||
import HoganJsUtils from '../hoganjs-utils';
|
||||
import { LineType, DiffLine, DiffFile, LineMatchingType } from '../types';
|
||||
import { CSSLineClass } from '../render-utils';
|
||||
|
||||
describe("SideBySideRenderer", () => {
|
||||
describe("generateEmptyDiff", () => {
|
||||
it("should return an empty diff", () => {
|
||||
describe('SideBySideRenderer', () => {
|
||||
describe('generateEmptyDiff', () => {
|
||||
it('should return an empty diff', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
|
||||
const fileHtml = sideBySideRenderer.generateEmptyDiff();
|
||||
|
|
@ -24,8 +24,8 @@ describe("SideBySideRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("generateSideBySideFileHtml", () => {
|
||||
it("should generate lines with the right prefixes", () => {
|
||||
describe('generateSideBySideFileHtml', () => {
|
||||
it('should generate lines with the right prefixes', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
|
||||
|
||||
|
|
@ -35,44 +35,44 @@ describe("SideBySideRenderer", () => {
|
|||
{
|
||||
lines: [
|
||||
{
|
||||
content: " context",
|
||||
content: ' context',
|
||||
type: LineType.CONTEXT,
|
||||
oldNumber: 19,
|
||||
newNumber: 19
|
||||
newNumber: 19,
|
||||
},
|
||||
{
|
||||
content: "-removed",
|
||||
content: '-removed',
|
||||
type: LineType.DELETE,
|
||||
oldNumber: 20,
|
||||
newNumber: undefined
|
||||
newNumber: undefined,
|
||||
},
|
||||
{
|
||||
content: "+added",
|
||||
content: '+added',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 20
|
||||
newNumber: 20,
|
||||
},
|
||||
{
|
||||
content: "+another added",
|
||||
content: '+another added',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 21
|
||||
}
|
||||
newNumber: 21,
|
||||
},
|
||||
],
|
||||
oldStartLine: 19,
|
||||
newStartLine: 19,
|
||||
header: "@@ -19,7 +19,7 @@"
|
||||
}
|
||||
header: '@@ -19,7 +19,7 @@',
|
||||
},
|
||||
],
|
||||
deletedLines: 1,
|
||||
addedLines: 2,
|
||||
checksumBefore: "fc56817",
|
||||
checksumAfter: "e8e7e49",
|
||||
mode: "100644",
|
||||
oldName: "coverage.init",
|
||||
language: "init",
|
||||
newName: "coverage.init",
|
||||
isCombined: false
|
||||
checksumBefore: 'fc56817',
|
||||
checksumAfter: 'e8e7e49',
|
||||
mode: '100644',
|
||||
oldName: 'coverage.init',
|
||||
language: 'init',
|
||||
newName: 'coverage.init',
|
||||
isCombined: false,
|
||||
};
|
||||
|
||||
const fileHtml = sideBySideRenderer.generateFileHtml(file);
|
||||
|
|
@ -156,15 +156,15 @@ describe("SideBySideRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("generateSingleLineHtml", () => {
|
||||
it("should work for insertions", () => {
|
||||
describe('generateSingleLineHtml', () => {
|
||||
it('should work for insertions', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
|
||||
const fileHtml = sideBySideRenderer.generateLineHtml(undefined, {
|
||||
type: CSSLineClass.INSERTS,
|
||||
prefix: "+",
|
||||
content: "test",
|
||||
number: 30
|
||||
prefix: '+',
|
||||
content: 'test',
|
||||
number: 30,
|
||||
});
|
||||
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
|
|
@ -194,17 +194,17 @@ describe("SideBySideRenderer", () => {
|
|||
}
|
||||
`);
|
||||
});
|
||||
it("should work for deletions", () => {
|
||||
it('should work for deletions', () => {
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
const sideBySideRenderer = new SideBySideRenderer(hoganUtils, {});
|
||||
const fileHtml = sideBySideRenderer.generateLineHtml(
|
||||
{
|
||||
type: CSSLineClass.DELETES,
|
||||
prefix: "-",
|
||||
content: "test",
|
||||
number: 30
|
||||
prefix: '-',
|
||||
content: 'test',
|
||||
number: 30,
|
||||
},
|
||||
undefined
|
||||
undefined,
|
||||
);
|
||||
|
||||
expect(fileHtml).toMatchInlineSnapshot(`
|
||||
|
|
@ -236,42 +236,42 @@ describe("SideBySideRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("generateSideBySideJsonHtml", () => {
|
||||
it("should work for list of files", () => {
|
||||
describe('generateSideBySideJsonHtml', () => {
|
||||
it('should work for list of files', () => {
|
||||
const exampleJson: DiffFile[] = [
|
||||
{
|
||||
blocks: [
|
||||
{
|
||||
lines: [
|
||||
{
|
||||
content: "-test",
|
||||
content: '-test',
|
||||
type: LineType.DELETE,
|
||||
oldNumber: 1,
|
||||
newNumber: undefined
|
||||
newNumber: undefined,
|
||||
},
|
||||
{
|
||||
content: "+test1r",
|
||||
content: '+test1r',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 1
|
||||
}
|
||||
newNumber: 1,
|
||||
},
|
||||
],
|
||||
oldStartLine: 1,
|
||||
oldStartLine2: undefined,
|
||||
newStartLine: 1,
|
||||
header: "@@ -1 +1 @@"
|
||||
}
|
||||
header: '@@ -1 +1 @@',
|
||||
},
|
||||
],
|
||||
deletedLines: 1,
|
||||
addedLines: 1,
|
||||
checksumBefore: "0000001",
|
||||
checksumAfter: "0ddf2ba",
|
||||
oldName: "sample",
|
||||
language: "txt",
|
||||
newName: "sample",
|
||||
checksumBefore: '0000001',
|
||||
checksumAfter: '0ddf2ba',
|
||||
oldName: 'sample',
|
||||
language: 'txt',
|
||||
newName: 'sample',
|
||||
isCombined: false,
|
||||
isGitDiff: true
|
||||
}
|
||||
isGitDiff: true,
|
||||
},
|
||||
];
|
||||
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
|
|
@ -341,18 +341,18 @@ describe("SideBySideRenderer", () => {
|
|||
</div>"
|
||||
`);
|
||||
});
|
||||
it("should work for files without blocks", () => {
|
||||
it('should work for files without blocks', () => {
|
||||
const exampleJson: DiffFile[] = [
|
||||
{
|
||||
blocks: [],
|
||||
oldName: "sample",
|
||||
language: "js",
|
||||
newName: "sample",
|
||||
oldName: 'sample',
|
||||
language: 'js',
|
||||
newName: 'sample',
|
||||
isCombined: false,
|
||||
addedLines: 0,
|
||||
deletedLines: 0,
|
||||
isGitDiff: false
|
||||
}
|
||||
isGitDiff: false,
|
||||
},
|
||||
];
|
||||
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
|
|
@ -400,24 +400,24 @@ describe("SideBySideRenderer", () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe("processLines", () => {
|
||||
it("should process file lines", () => {
|
||||
describe('processLines', () => {
|
||||
it('should process file lines', () => {
|
||||
const oldLines: DiffLine[] = [
|
||||
{
|
||||
content: "-test",
|
||||
content: '-test',
|
||||
type: LineType.DELETE,
|
||||
oldNumber: 1,
|
||||
newNumber: undefined
|
||||
}
|
||||
newNumber: undefined,
|
||||
},
|
||||
];
|
||||
|
||||
const newLines: DiffLine[] = [
|
||||
{
|
||||
content: "+test1r",
|
||||
content: '+test1r',
|
||||
type: LineType.INSERT,
|
||||
oldNumber: undefined,
|
||||
newNumber: 1
|
||||
}
|
||||
newNumber: 1,
|
||||
},
|
||||
];
|
||||
|
||||
const hoganUtils = new HoganJsUtils({});
|
||||
|
|
|
|||
|
|
@ -1,31 +1,31 @@
|
|||
import { escapeForRegExp, unifyPath, hashCode } from "../utils";
|
||||
import { escapeForRegExp, unifyPath, hashCode } from '../utils';
|
||||
|
||||
describe("Utils", () => {
|
||||
describe("escapeForRegExp", () => {
|
||||
it("should escape markdown link text", () => {
|
||||
const result = escapeForRegExp("[Link](https://diff2html.xyz)");
|
||||
expect(result).toEqual("\\[Link\\]\\(https:\\/\\/diff2html\\.xyz\\)");
|
||||
describe('Utils', () => {
|
||||
describe('escapeForRegExp', () => {
|
||||
it('should escape markdown link text', () => {
|
||||
const result = escapeForRegExp('[Link](https://diff2html.xyz)');
|
||||
expect(result).toEqual('\\[Link\\]\\(https:\\/\\/diff2html\\.xyz\\)');
|
||||
});
|
||||
it("should escape all dangerous characters", () => {
|
||||
const result = escapeForRegExp("-[]/{}()*+?.\\^$|");
|
||||
expect(result).toEqual("\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|");
|
||||
it('should escape all dangerous characters', () => {
|
||||
const result = escapeForRegExp('-[]/{}()*+?.\\^$|');
|
||||
expect(result).toEqual('\\-\\[\\]\\/\\{\\}\\(\\)\\*\\+\\?\\.\\\\\\^\\$\\|');
|
||||
});
|
||||
});
|
||||
|
||||
describe("unifyPath", () => {
|
||||
it("should unify windows style path", () => {
|
||||
const result = unifyPath("\\Users\\Downloads\\diff.html");
|
||||
expect(result).toEqual("/Users/Downloads/diff.html");
|
||||
describe('unifyPath', () => {
|
||||
it('should unify windows style path', () => {
|
||||
const result = unifyPath('\\Users\\Downloads\\diff.html');
|
||||
expect(result).toEqual('/Users/Downloads/diff.html');
|
||||
});
|
||||
});
|
||||
|
||||
describe("hashCode", () => {
|
||||
it("should create consistent hash for a text piece", () => {
|
||||
const string = "/home/diff2html/diff.html";
|
||||
describe('hashCode', () => {
|
||||
it('should create consistent hash for a text piece', () => {
|
||||
const string = '/home/diff2html/diff.html';
|
||||
expect(hashCode(string)).toEqual(hashCode(string));
|
||||
});
|
||||
it("should create different hash for different text pieces", () => {
|
||||
expect(hashCode("/home/diff2html/diff1.html")).not.toEqual(hashCode("/home/diff2html/diff2.html"));
|
||||
it('should create different hash for different text pieces', () => {
|
||||
expect(hashCode('/home/diff2html/diff1.html')).not.toEqual(hashCode('/home/diff2html/diff2.html'));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
|
|
|||
|
|
@ -1,5 +1,5 @@
|
|||
import { DiffFile, DiffBlock, DiffLine, LineType } from "./types";
|
||||
import { escapeForRegExp } from "./utils";
|
||||
import { DiffFile, DiffBlock, DiffLine, LineType } from './types';
|
||||
import { escapeForRegExp } from './utils';
|
||||
|
||||
export interface DiffParserConfig {
|
||||
srcPrefix?: string;
|
||||
|
|
@ -7,7 +7,7 @@ export interface DiffParserConfig {
|
|||
}
|
||||
|
||||
function getExtension(filename: string, language: string): string {
|
||||
const filenameParts = filename.split(".");
|
||||
const filenameParts = filename.split('.');
|
||||
return filenameParts.length > 1 ? filenameParts[filenameParts.length - 1] : language;
|
||||
}
|
||||
|
||||
|
|
@ -15,7 +15,7 @@ function startsWithAny(str: string, prefixes: string[]): boolean {
|
|||
return prefixes.reduce<boolean>((startsWith, prefix) => startsWith || str.startsWith(prefix), false);
|
||||
}
|
||||
|
||||
const baseDiffFilenamePrefixes = ["a/", "b/", "i/", "w/", "c/", "o/"];
|
||||
const baseDiffFilenamePrefixes = ['a/', 'b/', 'i/', 'w/', 'c/', 'o/'];
|
||||
function getFilename(line: string, linePrefix?: string, extraPrefix?: string): string {
|
||||
const prefixes = extraPrefix !== undefined ? [...baseDiffFilenamePrefixes, extraPrefix] : baseDiffFilenamePrefixes;
|
||||
|
||||
|
|
@ -23,22 +23,22 @@ function getFilename(line: string, linePrefix?: string, extraPrefix?: string): s
|
|||
? new RegExp(`^${escapeForRegExp(linePrefix)} "?(.+?)"?$`)
|
||||
: new RegExp('^"?(.+?)"?$');
|
||||
|
||||
const [, filename = ""] = FilenameRegExp.exec(line) || [];
|
||||
const [, filename = ''] = FilenameRegExp.exec(line) || [];
|
||||
const matchingPrefix = prefixes.find(p => filename.indexOf(p) === 0);
|
||||
const fnameWithoutPrefix = matchingPrefix ? filename.slice(matchingPrefix.length) : filename;
|
||||
|
||||
// Cleanup timestamps generated by the unified diff (diff command) as specified in
|
||||
// https://www.gnu.org/software/diffutils/manual/html_node/Detailed-Unified.html
|
||||
// Ie: 2016-10-25 11:37:14.000000000 +0200
|
||||
return fnameWithoutPrefix.replace(/\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)? [-+]\d{4}.*$/, "");
|
||||
return fnameWithoutPrefix.replace(/\s+\d{4}-\d{2}-\d{2} \d{2}:\d{2}:\d{2}(?:\.\d+)? [+-]\d{4}.*$/, '');
|
||||
}
|
||||
|
||||
function getSrcFilename(line: string, srcPrefix?: string): string | undefined {
|
||||
return getFilename(line, "---", srcPrefix);
|
||||
return getFilename(line, '---', srcPrefix);
|
||||
}
|
||||
|
||||
function getDstFilename(line: string, dstPrefix?: string): string | undefined {
|
||||
return getFilename(line, "+++", dstPrefix);
|
||||
return getFilename(line, '+++', dstPrefix);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -61,9 +61,9 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
let possibleNewName: string | null = null;
|
||||
|
||||
/* Diff Header */
|
||||
const oldFileNameHeader = "--- ";
|
||||
const newFileNameHeader = "+++ ";
|
||||
const hunkHeaderPrefix = "@@";
|
||||
const oldFileNameHeader = '--- ';
|
||||
const newFileNameHeader = '+++ ';
|
||||
const hunkHeaderPrefix = '@@';
|
||||
|
||||
/* Diff */
|
||||
const oldMode = /^old mode (\d{6})/;
|
||||
|
|
@ -79,21 +79,21 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
|
||||
const similarityIndex = /^similarity index (\d+)%/;
|
||||
const dissimilarityIndex = /^dissimilarity index (\d+)%/;
|
||||
const index = /^index ([0-9a-z]+)\.\.([0-9a-z]+)\s*(\d{6})?/;
|
||||
const index = /^index ([\da-z]+)\.\.([\da-z]+)\s*(\d{6})?/;
|
||||
|
||||
const binaryFiles = /^Binary files (.*) and (.*) differ/;
|
||||
const binaryDiff = /^GIT binary patch/;
|
||||
|
||||
/* Combined Diff */
|
||||
const combinedIndex = /^index ([0-9a-z]+),([0-9a-z]+)\.\.([0-9a-z]+)/;
|
||||
const combinedIndex = /^index ([\da-z]+),([\da-z]+)\.\.([\da-z]+)/;
|
||||
const combinedMode = /^mode (\d{6}),(\d{6})\.\.(\d{6})/;
|
||||
const combinedNewFile = /^new file mode (\d{6})/;
|
||||
const combinedDeletedFile = /^deleted file mode (\d{6}),(\d{6})/;
|
||||
|
||||
const diffLines = diffInput
|
||||
.replace(/\\ No newline at end of file/g, "")
|
||||
.replace(/\r\n?/g, "\n")
|
||||
.split("\n");
|
||||
.replace(/\\ No newline at end of file/g, '')
|
||||
.replace(/\r\n?/g, '\n')
|
||||
.split('\n');
|
||||
|
||||
/* Add previous block(if exists) before start a new file */
|
||||
function saveBlock(): void {
|
||||
|
|
@ -137,7 +137,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
currentFile = {
|
||||
blocks: [],
|
||||
deletedLines: 0,
|
||||
addedLines: 0
|
||||
addedLines: 0,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -172,7 +172,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
newLine = parseInt(values[3], 10);
|
||||
} else {
|
||||
if (line.startsWith(hunkHeaderPrefix)) {
|
||||
console.error("Failed to parse lines, starting in 0!");
|
||||
console.error('Failed to parse lines, starting in 0!');
|
||||
}
|
||||
|
||||
oldLine = 0;
|
||||
|
|
@ -189,7 +189,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
oldStartLine: oldLine,
|
||||
oldStartLine2: oldLine2,
|
||||
newStartLine: newLine,
|
||||
header: line
|
||||
header: line,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -199,11 +199,11 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
// eslint-disable-next-line
|
||||
// @ts-ignore
|
||||
const currentLine: DiffLine = {
|
||||
content: line
|
||||
content: line,
|
||||
};
|
||||
|
||||
const addedPrefixes = currentFile.isCombined ? ["+ ", " +", "++"] : ["+"];
|
||||
const deletedPrefixes = currentFile.isCombined ? ["- ", " -", "--"] : ["-"];
|
||||
const addedPrefixes = currentFile.isCombined ? ['+ ', ' +', '++'] : ['+'];
|
||||
const deletedPrefixes = currentFile.isCombined ? ['- ', ' -', '--'] : ['-'];
|
||||
|
||||
if (startsWithAny(line, addedPrefixes)) {
|
||||
currentFile.addedLines++;
|
||||
|
|
@ -232,7 +232,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
let idx = lineIdx;
|
||||
|
||||
while (idx < diffLines.length - 3) {
|
||||
if (line.startsWith("diff")) {
|
||||
if (line.startsWith('diff')) {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -254,7 +254,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
// Unmerged paths, and possibly other non-diffable files
|
||||
// https://github.com/scottgonzalez/pretty-diff/issues/11
|
||||
// Also, remove some useless lines
|
||||
if (!line || line.startsWith("*")) {
|
||||
if (!line || line.startsWith('*')) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
@ -265,7 +265,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
const nxtLine = diffLines[lineIndex + 1];
|
||||
const afterNxtLine = diffLines[lineIndex + 2];
|
||||
|
||||
if (line.startsWith("diff")) {
|
||||
if (line.startsWith('diff')) {
|
||||
startFile();
|
||||
|
||||
// diff --git a/blocked_delta_results.png b/blocked_delta_results.png
|
||||
|
|
@ -276,7 +276,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
}
|
||||
|
||||
if (currentFile === null) {
|
||||
throw new Error("Where is my file !!!");
|
||||
throw new Error('Where is my file !!!');
|
||||
}
|
||||
|
||||
currentFile.isGitDiff = true;
|
||||
|
|
@ -311,7 +311,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
if (
|
||||
currentFile &&
|
||||
!currentFile.oldName &&
|
||||
line.startsWith("--- ") &&
|
||||
line.startsWith('--- ') &&
|
||||
(values = getSrcFilename(line, config.srcPrefix))
|
||||
) {
|
||||
currentFile.oldName = values;
|
||||
|
|
@ -326,7 +326,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
if (
|
||||
currentFile &&
|
||||
!currentFile.newName &&
|
||||
line.startsWith("+++ ") &&
|
||||
line.startsWith('+++ ') &&
|
||||
(values = getDstFilename(line, config.dstPrefix))
|
||||
) {
|
||||
currentFile.newName = values;
|
||||
|
|
@ -350,7 +350,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
* 2. Old line starts with: -
|
||||
* 3. Context line starts with: <SPACE>
|
||||
*/
|
||||
if (currentBlock && (line.startsWith("+") || line.startsWith("-") || line.startsWith(" "))) {
|
||||
if (currentBlock && (line.startsWith('+') || line.startsWith('-') || line.startsWith(' '))) {
|
||||
createLine(line);
|
||||
return;
|
||||
}
|
||||
|
|
@ -358,7 +358,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
const doesNotExistHunkHeader = !existHunkHeader(line, lineIndex);
|
||||
|
||||
if (currentFile === null) {
|
||||
throw new Error("Where is my file !!!");
|
||||
throw new Error('Where is my file !!!');
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -399,7 +399,7 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
currentFile.isBinary = true;
|
||||
currentFile.oldName = getFilename(values[1], undefined, config.srcPrefix);
|
||||
currentFile.newName = getFilename(values[2], undefined, config.dstPrefix);
|
||||
startBlock("Binary file");
|
||||
startBlock('Binary file');
|
||||
} else if (binaryDiff.test(line)) {
|
||||
currentFile.isBinary = true;
|
||||
startBlock(line);
|
||||
|
|
@ -417,9 +417,11 @@ export function parse(diffInput: string, config: DiffParserConfig = {}): DiffFil
|
|||
} 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;
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
import * as DiffParser from "./diff-parser";
|
||||
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";
|
||||
import HoganJsUtils, { HoganJsUtilsConfig } from "./hoganjs-utils";
|
||||
import * as DiffParser from './diff-parser';
|
||||
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';
|
||||
import HoganJsUtils, { HoganJsUtilsConfig } from './hoganjs-utils';
|
||||
|
||||
export interface Diff2HtmlConfig
|
||||
extends DiffParser.DiffParserConfig,
|
||||
|
|
@ -18,7 +18,7 @@ export const defaultDiff2HtmlConfig = {
|
|||
...defaultLineByLineRendererConfig,
|
||||
...defaultSideBySideRendererConfig,
|
||||
outputFormat: OutputFormatType.LINE_BY_LINE,
|
||||
drawFileList: true
|
||||
drawFileList: true,
|
||||
};
|
||||
|
||||
export function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): DiffFile[] {
|
||||
|
|
@ -28,14 +28,14 @@ export function parse(diffInput: string, configuration: Diff2HtmlConfig = {}): D
|
|||
export function html(diffInput: string | DiffFile[], configuration: Diff2HtmlConfig = {}): string {
|
||||
const config = { ...defaultDiff2HtmlConfig, ...configuration };
|
||||
|
||||
const diffJson = typeof diffInput === "string" ? DiffParser.parse(diffInput, config) : diffInput;
|
||||
const diffJson = typeof diffInput === 'string' ? DiffParser.parse(diffInput, config) : diffInput;
|
||||
|
||||
const hoganUtils = new HoganJsUtils(config);
|
||||
|
||||
const fileList = config.drawFileList ? fileListPrinter.render(diffJson, hoganUtils) : "";
|
||||
const fileList = config.drawFileList ? fileListPrinter.render(diffJson, hoganUtils) : '';
|
||||
|
||||
const diffOutput =
|
||||
config.outputFormat === "side-by-side"
|
||||
config.outputFormat === 'side-by-side'
|
||||
? new SideBySideRenderer(hoganUtils, config).render(diffJson)
|
||||
: new LineByLineRenderer(hoganUtils, config).render(diffJson);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,33 +1,33 @@
|
|||
import * as renderUtils from "./render-utils";
|
||||
import HoganJsUtils from "./hoganjs-utils";
|
||||
import { DiffFile } from "./types";
|
||||
import * as renderUtils from './render-utils';
|
||||
import HoganJsUtils from './hoganjs-utils';
|
||||
import { DiffFile } from './types';
|
||||
|
||||
const baseTemplatesPath = "file-summary";
|
||||
const iconsBaseTemplatesPath = "icon";
|
||||
const baseTemplatesPath = 'file-summary';
|
||||
const iconsBaseTemplatesPath = 'icon';
|
||||
|
||||
export function render(diffFiles: DiffFile[], hoganUtils: HoganJsUtils): string {
|
||||
const files = diffFiles
|
||||
.map(file =>
|
||||
hoganUtils.render(
|
||||
baseTemplatesPath,
|
||||
"line",
|
||||
'line',
|
||||
{
|
||||
fileHtmlId: renderUtils.getHtmlId(file),
|
||||
oldName: file.oldName,
|
||||
newName: file.newName,
|
||||
fileName: renderUtils.filenameDiff(file),
|
||||
deletedLines: "-" + file.deletedLines,
|
||||
addedLines: "+" + file.addedLines
|
||||
deletedLines: '-' + file.deletedLines,
|
||||
addedLines: '+' + file.addedLines,
|
||||
},
|
||||
{
|
||||
fileIcon: hoganUtils.template(iconsBaseTemplatesPath, renderUtils.getFileIcon(file))
|
||||
}
|
||||
fileIcon: hoganUtils.template(iconsBaseTemplatesPath, renderUtils.getFileIcon(file)),
|
||||
},
|
||||
),
|
||||
)
|
||||
)
|
||||
.join("\n");
|
||||
.join('\n');
|
||||
|
||||
return hoganUtils.render(baseTemplatesPath, "wrapper", {
|
||||
return hoganUtils.render(baseTemplatesPath, 'wrapper', {
|
||||
filesNumber: diffFiles.length,
|
||||
files: files
|
||||
files: files,
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import * as Hogan from "hogan.js";
|
||||
import * as Hogan from 'hogan.js';
|
||||
|
||||
import { defaultTemplates } from "./diff2html-templates";
|
||||
import { defaultTemplates } from './diff2html-templates';
|
||||
|
||||
export interface RawTemplates {
|
||||
[name: string]: string;
|
||||
|
|
@ -24,7 +24,7 @@ export default class HoganJsUtils {
|
|||
const compiledTemplate: Hogan.Template = Hogan.compile(templateString, { asString: false });
|
||||
return { ...previousTemplates, [name]: compiledTemplate };
|
||||
},
|
||||
{}
|
||||
{},
|
||||
);
|
||||
|
||||
this.preCompiledTemplates = { ...defaultTemplates, ...compiledTemplates, ...compiledRawTemplates };
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import HoganJsUtils from "./hoganjs-utils";
|
||||
import * as Rematch from "./rematch";
|
||||
import * as renderUtils from "./render-utils";
|
||||
import HoganJsUtils from './hoganjs-utils';
|
||||
import * as Rematch from './rematch';
|
||||
import * as renderUtils from './render-utils';
|
||||
import {
|
||||
DiffFile,
|
||||
DiffLine,
|
||||
|
|
@ -9,8 +9,8 @@ import {
|
|||
DiffLineDeleted,
|
||||
DiffLineContent,
|
||||
DiffLineContext,
|
||||
DiffLineInserted
|
||||
} from "./types";
|
||||
DiffLineInserted,
|
||||
} from './types';
|
||||
|
||||
export interface LineByLineRendererConfig extends renderUtils.RenderConfig {
|
||||
renderNothingWhenEmpty?: boolean;
|
||||
|
|
@ -22,13 +22,13 @@ export const defaultLineByLineRendererConfig = {
|
|||
...renderUtils.defaultRenderConfig,
|
||||
renderNothingWhenEmpty: false,
|
||||
matchingMaxComparisons: 2500,
|
||||
maxLineSizeInBlockForComparison: 200
|
||||
maxLineSizeInBlockForComparison: 200,
|
||||
};
|
||||
|
||||
const genericTemplatesPath = "generic";
|
||||
const baseTemplatesPath = "line-by-line";
|
||||
const iconsBaseTemplatesPath = "icon";
|
||||
const tagsBaseTemplatesPath = "tag";
|
||||
const genericTemplatesPath = 'generic';
|
||||
const baseTemplatesPath = 'line-by-line';
|
||||
const iconsBaseTemplatesPath = 'icon';
|
||||
const tagsBaseTemplatesPath = 'tag';
|
||||
|
||||
export default class LineByLineRenderer {
|
||||
private readonly hoganUtils: HoganJsUtils;
|
||||
|
|
@ -50,17 +50,17 @@ export default class LineByLineRenderer {
|
|||
}
|
||||
return this.makeFileDiffHtml(file, diffs);
|
||||
})
|
||||
.join("\n");
|
||||
.join('\n');
|
||||
|
||||
return this.hoganUtils.render(genericTemplatesPath, "wrapper", { content: diffsHtml });
|
||||
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
|
||||
}
|
||||
|
||||
makeFileDiffHtml(file: DiffFile, diffs: string): string {
|
||||
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return "";
|
||||
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return '';
|
||||
|
||||
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, "file-diff");
|
||||
const filePathTemplate = this.hoganUtils.template(genericTemplatesPath, "file-path");
|
||||
const fileIconTemplate = this.hoganUtils.template(iconsBaseTemplatesPath, "file");
|
||||
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, 'file-diff');
|
||||
const filePathTemplate = this.hoganUtils.template(genericTemplatesPath, 'file-path');
|
||||
const fileIconTemplate = this.hoganUtils.template(iconsBaseTemplatesPath, 'file');
|
||||
const fileTagTemplate = this.hoganUtils.template(tagsBaseTemplatesPath, renderUtils.getFileIcon(file));
|
||||
|
||||
return fileDiffTemplate.render({
|
||||
|
|
@ -69,35 +69,35 @@ export default class LineByLineRenderer {
|
|||
diffs: diffs,
|
||||
filePath: filePathTemplate.render(
|
||||
{
|
||||
fileDiffName: renderUtils.filenameDiff(file)
|
||||
fileDiffName: renderUtils.filenameDiff(file),
|
||||
},
|
||||
{
|
||||
fileIcon: fileIconTemplate,
|
||||
fileTag: fileTagTemplate
|
||||
}
|
||||
)
|
||||
fileTag: fileTagTemplate,
|
||||
},
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
generateEmptyDiff(): string {
|
||||
return this.hoganUtils.render(genericTemplatesPath, "empty-diff", {
|
||||
contentClass: "d2h-code-line",
|
||||
CSSLineClass: renderUtils.CSSLineClass
|
||||
return this.hoganUtils.render(genericTemplatesPath, 'empty-diff', {
|
||||
contentClass: 'd2h-code-line',
|
||||
CSSLineClass: renderUtils.CSSLineClass,
|
||||
});
|
||||
}
|
||||
|
||||
generateFileHtml(file: DiffFile): string {
|
||||
const matcher = Rematch.newMatcherFn(
|
||||
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content)
|
||||
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content),
|
||||
);
|
||||
|
||||
return file.blocks
|
||||
.map(block => {
|
||||
let lines = this.hoganUtils.render(genericTemplatesPath, "block-header", {
|
||||
let lines = this.hoganUtils.render(genericTemplatesPath, 'block-header', {
|
||||
CSSLineClass: renderUtils.CSSLineClass,
|
||||
blockHeader: block.header,
|
||||
lineClass: "d2h-code-linenumber",
|
||||
contentClass: "d2h-code-line"
|
||||
lineClass: 'd2h-code-linenumber',
|
||||
contentClass: 'd2h-code-line',
|
||||
});
|
||||
|
||||
this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => {
|
||||
|
|
@ -115,7 +115,7 @@ export default class LineByLineRenderer {
|
|||
prefix: prefix,
|
||||
content: content,
|
||||
oldNumber: line.oldNumber,
|
||||
newNumber: line.newNumber
|
||||
newNumber: line.newNumber,
|
||||
});
|
||||
});
|
||||
} else if (oldLines.length || newLines.length) {
|
||||
|
|
@ -123,13 +123,13 @@ export default class LineByLineRenderer {
|
|||
lines += left;
|
||||
lines += right;
|
||||
} else {
|
||||
console.error("Unknown state reached while processing groups of lines", contextLines, oldLines, newLines);
|
||||
console.error('Unknown state reached while processing groups of lines', contextLines, oldLines, newLines);
|
||||
}
|
||||
});
|
||||
|
||||
return lines;
|
||||
})
|
||||
.join("\n");
|
||||
.join('\n');
|
||||
}
|
||||
|
||||
applyLineGroupping(block: DiffBlock): DiffLineGroups {
|
||||
|
|
@ -173,27 +173,25 @@ export default class LineByLineRenderer {
|
|||
applyRematchMatching(
|
||||
oldLines: DiffLine[],
|
||||
newLines: DiffLine[],
|
||||
matcher: Rematch.MatcherFn<DiffLine>
|
||||
matcher: Rematch.MatcherFn<DiffLine>,
|
||||
): DiffLine[][][] {
|
||||
const comparisons = oldLines.length * newLines.length;
|
||||
const maxLineSizeInBlock = Math.max.apply(
|
||||
null,
|
||||
[0].concat(oldLines.concat(newLines).map(elem => elem.content.length))
|
||||
[0].concat(oldLines.concat(newLines).map(elem => elem.content.length)),
|
||||
);
|
||||
const doMatching =
|
||||
comparisons < this.config.matchingMaxComparisons &&
|
||||
maxLineSizeInBlock < this.config.maxLineSizeInBlockForComparison &&
|
||||
(this.config.matching === "lines" || this.config.matching === "words");
|
||||
(this.config.matching === 'lines' || this.config.matching === 'words');
|
||||
|
||||
const matches = doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]];
|
||||
|
||||
return matches;
|
||||
return doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]];
|
||||
}
|
||||
|
||||
processChangedLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
|
||||
const fileHtml = {
|
||||
right: "",
|
||||
left: ""
|
||||
right: '',
|
||||
left: '',
|
||||
};
|
||||
|
||||
const maxLinesNumber = Math.max(oldLines.length, newLines.length);
|
||||
|
|
@ -213,14 +211,14 @@ export default class LineByLineRenderer {
|
|||
? {
|
||||
prefix: diff.oldLine.prefix,
|
||||
content: diff.oldLine.content,
|
||||
type: renderUtils.CSSLineClass.DELETE_CHANGES
|
||||
type: renderUtils.CSSLineClass.DELETE_CHANGES,
|
||||
}
|
||||
: {
|
||||
...renderUtils.deconstructLine(oldLine.content, isCombined),
|
||||
type: renderUtils.toCSSClass(oldLine.type)
|
||||
type: renderUtils.toCSSClass(oldLine.type),
|
||||
}),
|
||||
oldNumber: oldLine.oldNumber,
|
||||
newNumber: oldLine.newNumber
|
||||
newNumber: oldLine.newNumber,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
|
@ -231,14 +229,14 @@ export default class LineByLineRenderer {
|
|||
? {
|
||||
prefix: diff.newLine.prefix,
|
||||
content: diff.newLine.content,
|
||||
type: renderUtils.CSSLineClass.INSERT_CHANGES
|
||||
type: renderUtils.CSSLineClass.INSERT_CHANGES,
|
||||
}
|
||||
: {
|
||||
...renderUtils.deconstructLine(newLine.content, isCombined),
|
||||
type: renderUtils.toCSSClass(newLine.type)
|
||||
type: renderUtils.toCSSClass(newLine.type),
|
||||
}),
|
||||
oldNumber: newLine.oldNumber,
|
||||
newNumber: newLine.newNumber
|
||||
newNumber: newLine.newNumber,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
|
@ -253,25 +251,25 @@ export default class LineByLineRenderer {
|
|||
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
|
||||
return {
|
||||
left: this.generateSingleLineHtml(oldLine),
|
||||
right: this.generateSingleLineHtml(newLine)
|
||||
right: this.generateSingleLineHtml(newLine),
|
||||
};
|
||||
}
|
||||
|
||||
generateSingleLineHtml(line?: DiffPreparedLine): string {
|
||||
if (line === undefined) return "";
|
||||
if (line === undefined) return '';
|
||||
|
||||
const lineNumberHtml = this.hoganUtils.render(baseTemplatesPath, "numbers", {
|
||||
oldNumber: line.oldNumber || "",
|
||||
newNumber: line.newNumber || ""
|
||||
const lineNumberHtml = this.hoganUtils.render(baseTemplatesPath, 'numbers', {
|
||||
oldNumber: line.oldNumber || '',
|
||||
newNumber: line.newNumber || '',
|
||||
});
|
||||
|
||||
return this.hoganUtils.render(genericTemplatesPath, "line", {
|
||||
return this.hoganUtils.render(genericTemplatesPath, 'line', {
|
||||
type: line.type,
|
||||
lineClass: "d2h-code-linenumber",
|
||||
contentClass: "d2h-code-line",
|
||||
prefix: line.prefix === " " ? " " : line.prefix,
|
||||
lineClass: 'd2h-code-linenumber',
|
||||
contentClass: 'd2h-code-line',
|
||||
prefix: line.prefix === ' ' ? ' ' : line.prefix,
|
||||
content: line.content,
|
||||
lineNumber: lineNumberHtml
|
||||
lineNumber: lineNumberHtml,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -279,7 +277,7 @@ export default class LineByLineRenderer {
|
|||
type DiffLineGroups = [
|
||||
(DiffLineContext & DiffLineContent)[],
|
||||
(DiffLineDeleted & DiffLineContent)[],
|
||||
(DiffLineInserted & DiffLineContent)[]
|
||||
(DiffLineInserted & DiffLineContent)[],
|
||||
][];
|
||||
|
||||
type DiffPreparedLine = {
|
||||
|
|
|
|||
|
|
@ -53,8 +53,8 @@ export function levenshtein(a: string, b: string): number {
|
|||
matrix[i - 1][j - 1] + 1, // Substitution
|
||||
Math.min(
|
||||
matrix[i][j - 1] + 1, // Insertion
|
||||
matrix[i - 1][j] + 1
|
||||
)
|
||||
matrix[i - 1][j] + 1,
|
||||
),
|
||||
); // Deletion
|
||||
}
|
||||
}
|
||||
|
|
@ -70,9 +70,7 @@ export function newDistanceFn<T>(str: (value: T) => string): DistanceFn<T> {
|
|||
const xValue = str(x).trim();
|
||||
const yValue = str(y).trim();
|
||||
const lev = levenshtein(xValue, yValue);
|
||||
const score = lev / (xValue.length + yValue.length);
|
||||
|
||||
return score;
|
||||
return lev / (xValue.length + yValue.length);
|
||||
};
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,16 +1,16 @@
|
|||
import * as jsDiff from "diff";
|
||||
import * as jsDiff from 'diff';
|
||||
|
||||
import { unifyPath, hashCode } from "./utils";
|
||||
import * as rematch from "./rematch";
|
||||
import { LineMatchingType, DiffStyleType, LineType, DiffLineParts, DiffFile, DiffFileName } from "./types";
|
||||
import { unifyPath, hashCode } from './utils';
|
||||
import * as rematch from './rematch';
|
||||
import { LineMatchingType, DiffStyleType, LineType, DiffLineParts, DiffFile, DiffFileName } from './types';
|
||||
|
||||
export enum CSSLineClass {
|
||||
INSERTS = "d2h-ins",
|
||||
DELETES = "d2h-del",
|
||||
CONTEXT = "d2h-cntx",
|
||||
INFO = "d2h-info",
|
||||
INSERT_CHANGES = "d2h-ins d2h-change",
|
||||
DELETE_CHANGES = "d2h-del d2h-change"
|
||||
INSERTS = 'd2h-ins',
|
||||
DELETES = 'd2h-del',
|
||||
CONTEXT = 'd2h-cntx',
|
||||
INFO = 'd2h-info',
|
||||
INSERT_CHANGES = 'd2h-ins d2h-change',
|
||||
DELETE_CHANGES = 'd2h-del d2h-change',
|
||||
}
|
||||
|
||||
export type HighlightedLines = {
|
||||
|
|
@ -35,23 +35,23 @@ export const defaultRenderConfig = {
|
|||
matching: LineMatchingType.NONE,
|
||||
matchWordsThreshold: 0.25,
|
||||
maxLineLengthHighlight: 10000,
|
||||
diffStyle: DiffStyleType.WORD
|
||||
diffStyle: DiffStyleType.WORD,
|
||||
};
|
||||
|
||||
const separator = "/";
|
||||
const separator = '/';
|
||||
const distance = rematch.newDistanceFn((change: jsDiff.Change) => change.value);
|
||||
const matcher = rematch.newMatcherFn(distance);
|
||||
|
||||
function isDevNullName(name: string): boolean {
|
||||
return name.indexOf("dev/null") !== -1;
|
||||
return name.indexOf('dev/null') !== -1;
|
||||
}
|
||||
|
||||
function removeInsElements(line: string): string {
|
||||
return line.replace(/(<ins[^>]*>((.|\n)*?)<\/ins>)/g, "");
|
||||
return line.replace(/(<ins[^>]*>((.|\n)*?)<\/ins>)/g, '');
|
||||
}
|
||||
|
||||
function removeDelElements(line: string): string {
|
||||
return line.replace(/(<del[^>]*>((.|\n)*?)<\/del>)/g, "");
|
||||
return line.replace(/(<del[^>]*>((.|\n)*?)<\/del>)/g, '');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -82,12 +82,12 @@ function prefixLength(isCombined: boolean): number {
|
|||
export function escapeForHtml(str: string): string {
|
||||
return str
|
||||
.slice(0)
|
||||
.replace(/&/g, "&")
|
||||
.replace(/</g, "<")
|
||||
.replace(/>/g, ">")
|
||||
.replace(/"/g, """)
|
||||
.replace(/'/g, "'")
|
||||
.replace(/\//g, "/");
|
||||
.replace(/&/g, '&')
|
||||
.replace(/</g, '<')
|
||||
.replace(/>/g, '>')
|
||||
.replace(/"/g, '"')
|
||||
.replace(/'/g, ''')
|
||||
.replace(/\//g, '/');
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -97,7 +97,7 @@ export function deconstructLine(line: string, isCombined: boolean): DiffLinePart
|
|||
const indexToSplit = prefixLength(isCombined);
|
||||
return {
|
||||
prefix: line.substring(0, indexToSplit),
|
||||
content: escapeForHtml(line.substring(indexToSplit))
|
||||
content: escapeForHtml(line.substring(indexToSplit)),
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -158,15 +158,15 @@ export function filenameDiff(file: DiffFileName): string {
|
|||
|
||||
if (finalPrefix.length && finalSuffix.length) {
|
||||
return (
|
||||
finalPrefix + separator + "{" + oldRemainingPath + " → " + newRemainingPath + "}" + separator + finalSuffix
|
||||
finalPrefix + separator + '{' + oldRemainingPath + ' → ' + newRemainingPath + '}' + separator + finalSuffix
|
||||
);
|
||||
} else if (finalPrefix.length) {
|
||||
return finalPrefix + separator + "{" + oldRemainingPath + " → " + newRemainingPath + "}";
|
||||
return finalPrefix + separator + '{' + oldRemainingPath + ' → ' + newRemainingPath + '}';
|
||||
} else if (finalSuffix.length) {
|
||||
return "{" + oldRemainingPath + " → " + newRemainingPath + "}" + separator + finalSuffix;
|
||||
return '{' + oldRemainingPath + ' → ' + newRemainingPath + '}' + separator + finalSuffix;
|
||||
}
|
||||
|
||||
return oldFilename + " → " + newFilename;
|
||||
return oldFilename + ' → ' + newFilename;
|
||||
} else if (!isDevNullName(newFilename)) {
|
||||
return newFilename;
|
||||
} else {
|
||||
|
|
@ -187,19 +187,19 @@ export function getHtmlId(file: DiffFileName): string {
|
|||
* Selects the correct icon name for the file
|
||||
*/
|
||||
export function getFileIcon(file: DiffFile): string {
|
||||
let templateName = "file-changed";
|
||||
let templateName = 'file-changed';
|
||||
|
||||
if (file.isRename) {
|
||||
templateName = "file-renamed";
|
||||
templateName = 'file-renamed';
|
||||
} else if (file.isCopy) {
|
||||
templateName = "file-renamed";
|
||||
templateName = 'file-renamed';
|
||||
} else if (file.isNew) {
|
||||
templateName = "file-added";
|
||||
templateName = 'file-added';
|
||||
} else if (file.isDeleted) {
|
||||
templateName = "file-deleted";
|
||||
templateName = 'file-deleted';
|
||||
} else if (file.newName !== file.oldName) {
|
||||
// If file is not Added, not Deleted and the names changed it must be a rename :)
|
||||
templateName = "file-renamed";
|
||||
templateName = 'file-renamed';
|
||||
}
|
||||
|
||||
return templateName;
|
||||
|
|
@ -212,7 +212,7 @@ export function diffHighlight(
|
|||
diffLine1: string,
|
||||
diffLine2: string,
|
||||
isCombined: boolean,
|
||||
config: RenderConfig = {}
|
||||
config: RenderConfig = {},
|
||||
): HighlightedLines {
|
||||
const { matching, maxLineLengthHighlight, matchWordsThreshold, diffStyle } = { ...defaultRenderConfig, ...config };
|
||||
|
||||
|
|
@ -223,22 +223,22 @@ export function diffHighlight(
|
|||
return {
|
||||
oldLine: {
|
||||
prefix: line1.prefix,
|
||||
content: line1.content
|
||||
content: line1.content,
|
||||
},
|
||||
newLine: {
|
||||
prefix: line2.prefix,
|
||||
content: line2.content
|
||||
}
|
||||
content: line2.content,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const diff =
|
||||
diffStyle === "char"
|
||||
diffStyle === 'char'
|
||||
? jsDiff.diffChars(line1.content, line2.content)
|
||||
: jsDiff.diffWordsWithSpace(line1.content, line2.content);
|
||||
|
||||
const changedWords: jsDiff.Change[] = [];
|
||||
if (diffStyle === "word" && matching === "words") {
|
||||
if (diffStyle === 'word' && matching === 'words') {
|
||||
const removed = diff.filter(element => element.removed);
|
||||
const added = diff.filter(element => element.added);
|
||||
const chunks = matcher(added, removed);
|
||||
|
|
@ -254,22 +254,22 @@ export function diffHighlight(
|
|||
}
|
||||
|
||||
const highlightedLine = diff.reduce((highlightedLine, part) => {
|
||||
const elemType = part.added ? "ins" : part.removed ? "del" : null;
|
||||
const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : "";
|
||||
const elemType = part.added ? 'ins' : part.removed ? 'del' : null;
|
||||
const addClass = changedWords.indexOf(part) > -1 ? ' class="d2h-change"' : '';
|
||||
|
||||
return elemType !== null
|
||||
? `${highlightedLine}<${elemType}${addClass}>${part.value}</${elemType}>`
|
||||
: `${highlightedLine}${part.value}`;
|
||||
}, "");
|
||||
}, '');
|
||||
|
||||
return {
|
||||
oldLine: {
|
||||
prefix: line1.prefix,
|
||||
content: removeInsElements(highlightedLine)
|
||||
content: removeInsElements(highlightedLine),
|
||||
},
|
||||
newLine: {
|
||||
prefix: line2.prefix,
|
||||
content: removeDelElements(highlightedLine)
|
||||
}
|
||||
content: removeDelElements(highlightedLine),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
import HoganJsUtils from "./hoganjs-utils";
|
||||
import * as Rematch from "./rematch";
|
||||
import * as renderUtils from "./render-utils";
|
||||
import HoganJsUtils from './hoganjs-utils';
|
||||
import * as Rematch from './rematch';
|
||||
import * as renderUtils from './render-utils';
|
||||
import {
|
||||
DiffLine,
|
||||
LineType,
|
||||
|
|
@ -9,8 +9,8 @@ import {
|
|||
DiffLineContext,
|
||||
DiffLineDeleted,
|
||||
DiffLineInserted,
|
||||
DiffLineContent
|
||||
} from "./types";
|
||||
DiffLineContent,
|
||||
} from './types';
|
||||
|
||||
export interface SideBySideRendererConfig extends renderUtils.RenderConfig {
|
||||
renderNothingWhenEmpty?: boolean;
|
||||
|
|
@ -22,13 +22,13 @@ export const defaultSideBySideRendererConfig = {
|
|||
...renderUtils.defaultRenderConfig,
|
||||
renderNothingWhenEmpty: false,
|
||||
matchingMaxComparisons: 2500,
|
||||
maxLineSizeInBlockForComparison: 200
|
||||
maxLineSizeInBlockForComparison: 200,
|
||||
};
|
||||
|
||||
const genericTemplatesPath = "generic";
|
||||
const baseTemplatesPath = "side-by-side";
|
||||
const iconsBaseTemplatesPath = "icon";
|
||||
const tagsBaseTemplatesPath = "tag";
|
||||
const genericTemplatesPath = 'generic';
|
||||
const baseTemplatesPath = 'side-by-side';
|
||||
const iconsBaseTemplatesPath = 'icon';
|
||||
const tagsBaseTemplatesPath = 'tag';
|
||||
|
||||
export default class SideBySideRenderer {
|
||||
private readonly hoganUtils: HoganJsUtils;
|
||||
|
|
@ -50,17 +50,17 @@ export default class SideBySideRenderer {
|
|||
}
|
||||
return this.makeFileDiffHtml(file, diffs);
|
||||
})
|
||||
.join("\n");
|
||||
.join('\n');
|
||||
|
||||
return this.hoganUtils.render(genericTemplatesPath, "wrapper", { content: diffsHtml });
|
||||
return this.hoganUtils.render(genericTemplatesPath, 'wrapper', { content: diffsHtml });
|
||||
}
|
||||
|
||||
makeFileDiffHtml(file: DiffFile, diffs: FileHtml): string {
|
||||
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return "";
|
||||
if (this.config.renderNothingWhenEmpty && Array.isArray(file.blocks) && file.blocks.length === 0) return '';
|
||||
|
||||
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, "file-diff");
|
||||
const filePathTemplate = this.hoganUtils.template(genericTemplatesPath, "file-path");
|
||||
const fileIconTemplate = this.hoganUtils.template(iconsBaseTemplatesPath, "file");
|
||||
const fileDiffTemplate = this.hoganUtils.template(baseTemplatesPath, 'file-diff');
|
||||
const filePathTemplate = this.hoganUtils.template(genericTemplatesPath, 'file-path');
|
||||
const fileIconTemplate = this.hoganUtils.template(iconsBaseTemplatesPath, 'file');
|
||||
const fileTagTemplate = this.hoganUtils.template(tagsBaseTemplatesPath, renderUtils.getFileIcon(file));
|
||||
|
||||
return fileDiffTemplate.render({
|
||||
|
|
@ -69,36 +69,36 @@ export default class SideBySideRenderer {
|
|||
diffs: diffs,
|
||||
filePath: filePathTemplate.render(
|
||||
{
|
||||
fileDiffName: renderUtils.filenameDiff(file)
|
||||
fileDiffName: renderUtils.filenameDiff(file),
|
||||
},
|
||||
{
|
||||
fileIcon: fileIconTemplate,
|
||||
fileTag: fileTagTemplate
|
||||
}
|
||||
)
|
||||
fileTag: fileTagTemplate,
|
||||
},
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
generateEmptyDiff(): FileHtml {
|
||||
return {
|
||||
right: "",
|
||||
left: this.hoganUtils.render(genericTemplatesPath, "empty-diff", {
|
||||
contentClass: "d2h-code-side-line",
|
||||
CSSLineClass: renderUtils.CSSLineClass
|
||||
})
|
||||
right: '',
|
||||
left: this.hoganUtils.render(genericTemplatesPath, 'empty-diff', {
|
||||
contentClass: 'd2h-code-side-line',
|
||||
CSSLineClass: renderUtils.CSSLineClass,
|
||||
}),
|
||||
};
|
||||
}
|
||||
|
||||
generateFileHtml(file: DiffFile): FileHtml {
|
||||
const matcher = Rematch.newMatcherFn(
|
||||
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content)
|
||||
Rematch.newDistanceFn((e: DiffLine) => renderUtils.deconstructLine(e.content, file.isCombined).content),
|
||||
);
|
||||
|
||||
return file.blocks
|
||||
.map(block => {
|
||||
const fileHtml = {
|
||||
left: this.makeHeaderHtml(block.header),
|
||||
right: this.makeHeaderHtml("")
|
||||
right: this.makeHeaderHtml(''),
|
||||
};
|
||||
|
||||
this.applyLineGroupping(block).forEach(([contextLines, oldLines, newLines]) => {
|
||||
|
|
@ -116,14 +116,14 @@ export default class SideBySideRenderer {
|
|||
type: renderUtils.CSSLineClass.CONTEXT,
|
||||
prefix: prefix,
|
||||
content: content,
|
||||
number: line.oldNumber
|
||||
number: line.oldNumber,
|
||||
},
|
||||
{
|
||||
type: renderUtils.CSSLineClass.CONTEXT,
|
||||
prefix: prefix,
|
||||
content: content,
|
||||
number: line.newNumber
|
||||
}
|
||||
number: line.newNumber,
|
||||
},
|
||||
);
|
||||
fileHtml.left += left;
|
||||
fileHtml.right += right;
|
||||
|
|
@ -133,7 +133,7 @@ export default class SideBySideRenderer {
|
|||
fileHtml.left += left;
|
||||
fileHtml.right += right;
|
||||
} else {
|
||||
console.error("Unknown state reached while processing groups of lines", contextLines, oldLines, newLines);
|
||||
console.error('Unknown state reached while processing groups of lines', contextLines, oldLines, newLines);
|
||||
}
|
||||
});
|
||||
|
||||
|
|
@ -143,7 +143,7 @@ export default class SideBySideRenderer {
|
|||
(accomulated, html) => {
|
||||
return { left: accomulated.left + html.left, right: accomulated.right + html.right };
|
||||
},
|
||||
{ left: "", right: "" }
|
||||
{ left: '', right: '' },
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -188,36 +188,34 @@ export default class SideBySideRenderer {
|
|||
applyRematchMatching(
|
||||
oldLines: DiffLine[],
|
||||
newLines: DiffLine[],
|
||||
matcher: Rematch.MatcherFn<DiffLine>
|
||||
matcher: Rematch.MatcherFn<DiffLine>,
|
||||
): DiffLine[][][] {
|
||||
const comparisons = oldLines.length * newLines.length;
|
||||
const maxLineSizeInBlock = Math.max.apply(
|
||||
null,
|
||||
[0].concat(oldLines.concat(newLines).map(elem => elem.content.length))
|
||||
[0].concat(oldLines.concat(newLines).map(elem => elem.content.length)),
|
||||
);
|
||||
const doMatching =
|
||||
comparisons < this.config.matchingMaxComparisons &&
|
||||
maxLineSizeInBlock < this.config.maxLineSizeInBlockForComparison &&
|
||||
(this.config.matching === "lines" || this.config.matching === "words");
|
||||
(this.config.matching === 'lines' || this.config.matching === 'words');
|
||||
|
||||
const matches = doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]];
|
||||
|
||||
return matches;
|
||||
return doMatching ? matcher(oldLines, newLines) : [[oldLines, newLines]];
|
||||
}
|
||||
|
||||
makeHeaderHtml(blockHeader: string): string {
|
||||
return this.hoganUtils.render(genericTemplatesPath, "block-header", {
|
||||
return this.hoganUtils.render(genericTemplatesPath, 'block-header', {
|
||||
CSSLineClass: renderUtils.CSSLineClass,
|
||||
blockHeader: blockHeader,
|
||||
lineClass: "d2h-code-side-linenumber",
|
||||
contentClass: "d2h-code-side-line"
|
||||
lineClass: 'd2h-code-side-linenumber',
|
||||
contentClass: 'd2h-code-side-line',
|
||||
});
|
||||
}
|
||||
|
||||
processChangedLines(isCombined: boolean, oldLines: DiffLine[], newLines: DiffLine[]): FileHtml {
|
||||
const fileHtml = {
|
||||
right: "",
|
||||
left: ""
|
||||
right: '',
|
||||
left: '',
|
||||
};
|
||||
|
||||
const maxLinesNumber = Math.max(oldLines.length, newLines.length);
|
||||
|
|
@ -237,13 +235,13 @@ export default class SideBySideRenderer {
|
|||
? {
|
||||
prefix: diff.oldLine.prefix,
|
||||
content: diff.oldLine.content,
|
||||
type: renderUtils.CSSLineClass.DELETE_CHANGES
|
||||
type: renderUtils.CSSLineClass.DELETE_CHANGES,
|
||||
}
|
||||
: {
|
||||
...renderUtils.deconstructLine(oldLine.content, isCombined),
|
||||
type: renderUtils.toCSSClass(oldLine.type)
|
||||
type: renderUtils.toCSSClass(oldLine.type),
|
||||
}),
|
||||
number: oldLine.oldNumber
|
||||
number: oldLine.oldNumber,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
|
@ -254,13 +252,13 @@ export default class SideBySideRenderer {
|
|||
? {
|
||||
prefix: diff.newLine.prefix,
|
||||
content: diff.newLine.content,
|
||||
type: renderUtils.CSSLineClass.INSERT_CHANGES
|
||||
type: renderUtils.CSSLineClass.INSERT_CHANGES,
|
||||
}
|
||||
: {
|
||||
...renderUtils.deconstructLine(newLine.content, isCombined),
|
||||
type: renderUtils.toCSSClass(newLine.type)
|
||||
type: renderUtils.toCSSClass(newLine.type),
|
||||
}),
|
||||
number: newLine.newNumber
|
||||
number: newLine.newNumber,
|
||||
}
|
||||
: undefined;
|
||||
|
||||
|
|
@ -275,21 +273,21 @@ export default class SideBySideRenderer {
|
|||
generateLineHtml(oldLine?: DiffPreparedLine, newLine?: DiffPreparedLine): FileHtml {
|
||||
return {
|
||||
left: this.generateSingleHtml(oldLine),
|
||||
right: this.generateSingleHtml(newLine)
|
||||
right: this.generateSingleHtml(newLine),
|
||||
};
|
||||
}
|
||||
|
||||
generateSingleHtml(line?: DiffPreparedLine): string {
|
||||
const lineClass = "d2h-code-side-linenumber";
|
||||
const contentClass = "d2h-code-side-line";
|
||||
const lineClass = 'd2h-code-side-linenumber';
|
||||
const contentClass = 'd2h-code-side-line';
|
||||
|
||||
return this.hoganUtils.render(genericTemplatesPath, "line", {
|
||||
return this.hoganUtils.render(genericTemplatesPath, 'line', {
|
||||
type: line?.type || `${renderUtils.CSSLineClass.CONTEXT} d2h-emptyplaceholder`,
|
||||
lineClass: line !== undefined ? lineClass : `${lineClass} d2h-code-side-emptyplaceholder`,
|
||||
contentClass: line !== undefined ? contentClass : `${contentClass} d2h-code-side-emptyplaceholder`,
|
||||
prefix: line?.prefix === " " ? " " : line?.prefix || " ",
|
||||
content: line?.content || " ",
|
||||
lineNumber: line?.number
|
||||
prefix: line?.prefix === ' ' ? ' ' : line?.prefix || ' ',
|
||||
content: line?.content || ' ',
|
||||
lineNumber: line?.number,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -297,7 +295,7 @@ export default class SideBySideRenderer {
|
|||
type DiffLineGroups = [
|
||||
(DiffLineContext & DiffLineContent)[],
|
||||
(DiffLineDeleted & DiffLineContent)[],
|
||||
(DiffLineInserted & DiffLineContent)[]
|
||||
(DiffLineInserted & DiffLineContent)[],
|
||||
][];
|
||||
|
||||
type DiffPreparedLine = {
|
||||
|
|
|
|||
20
src/types.ts
20
src/types.ts
|
|
@ -4,9 +4,9 @@ export type DiffLineParts = {
|
|||
};
|
||||
|
||||
export enum LineType {
|
||||
INSERT = "insert",
|
||||
DELETE = "delete",
|
||||
CONTEXT = "context"
|
||||
INSERT = 'insert',
|
||||
DELETE = 'delete',
|
||||
CONTEXT = 'context',
|
||||
}
|
||||
|
||||
export interface DiffLineDeleted {
|
||||
|
|
@ -70,17 +70,17 @@ export interface DiffFile extends DiffFileName {
|
|||
}
|
||||
|
||||
export enum OutputFormatType {
|
||||
LINE_BY_LINE = "line-by-line",
|
||||
SIDE_BY_SIDE = "side-by-side"
|
||||
LINE_BY_LINE = 'line-by-line',
|
||||
SIDE_BY_SIDE = 'side-by-side',
|
||||
}
|
||||
|
||||
export enum LineMatchingType {
|
||||
LINES = "lines",
|
||||
WORDS = "words",
|
||||
NONE = "none"
|
||||
LINES = 'lines',
|
||||
WORDS = 'words',
|
||||
NONE = 'none',
|
||||
}
|
||||
|
||||
export enum DiffStyleType {
|
||||
WORD = "word",
|
||||
CHAR = "char"
|
||||
WORD = 'word',
|
||||
CHAR = 'char',
|
||||
}
|
||||
|
|
|
|||
|
|
@ -51,7 +51,7 @@
|
|||
-ms-flex-align: center;
|
||||
align-items: center;
|
||||
width: 100%;
|
||||
font-family: "Source Sans Pro", "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-family: 'Source Sans Pro', 'Helvetica Neue', Helvetica, Arial, sans-serif;
|
||||
font-size: 15px;
|
||||
}
|
||||
|
||||
|
|
@ -70,7 +70,7 @@
|
|||
.d2h-diff-table {
|
||||
width: 100%;
|
||||
border-collapse: collapse;
|
||||
font-family: "Menlo", "Consolas", monospace;
|
||||
font-family: 'Menlo', 'Consolas', monospace;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
|
|
|
|||
228
src/ui/js/diff2html-ui-base.ts
Normal file
228
src/ui/js/diff2html-ui-base.ts
Normal file
|
|
@ -0,0 +1,228 @@
|
|||
import { HighlightJS, ICompiledMode, IHighlightResult, IAutoHighlightResult } from './highlight.js-interface';
|
||||
import { nodeStream, mergeStreams } from './highlight.js-helpers';
|
||||
|
||||
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from '../../diff2html';
|
||||
import { DiffFile } from '../../types';
|
||||
|
||||
export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
|
||||
synchronisedScroll?: boolean;
|
||||
highlight?: boolean;
|
||||
fileListToggle?: boolean;
|
||||
fileListStartVisible?: boolean;
|
||||
smartSelection?: boolean;
|
||||
}
|
||||
|
||||
export const defaultDiff2HtmlUIConfig = {
|
||||
...defaultDiff2HtmlConfig,
|
||||
synchronisedScroll: true,
|
||||
highlight: true,
|
||||
fileListToggle: true,
|
||||
fileListStartVisible: false,
|
||||
smartSelection: true,
|
||||
};
|
||||
|
||||
export class Diff2HtmlUI {
|
||||
readonly config: typeof defaultDiff2HtmlUIConfig;
|
||||
readonly diffHtml: string;
|
||||
readonly targetElement: HTMLElement;
|
||||
readonly hljs: HighlightJS | null = null;
|
||||
|
||||
currentSelectionColumnId = -1;
|
||||
|
||||
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}, hljs?: HighlightJS) {
|
||||
this.config = { ...defaultDiff2HtmlUIConfig, ...config };
|
||||
this.diffHtml = html(diffInput, this.config);
|
||||
this.targetElement = target;
|
||||
if (hljs !== undefined) this.hljs = hljs;
|
||||
}
|
||||
|
||||
draw(): void {
|
||||
this.targetElement.innerHTML = this.diffHtml;
|
||||
if (this.config.smartSelection) this.initSelection();
|
||||
if (this.config.synchronisedScroll) this.synchronisedScroll();
|
||||
if (this.config.highlight) this.highlightCode();
|
||||
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
|
||||
}
|
||||
|
||||
synchronisedScroll(): void {
|
||||
this.targetElement.querySelectorAll('.d2h-file-wrapper').forEach(wrapper => {
|
||||
const [left, right] = [].slice.call(wrapper.querySelectorAll('.d2h-file-side-diff')) as HTMLElement[];
|
||||
if (left === undefined || right === undefined) return;
|
||||
const onScroll = (event: Event): void => {
|
||||
if (event === null || event.target === null) return;
|
||||
if (event.target === left) {
|
||||
right.scrollTop = left.scrollTop;
|
||||
right.scrollLeft = left.scrollLeft;
|
||||
} else {
|
||||
left.scrollTop = right.scrollTop;
|
||||
left.scrollLeft = right.scrollLeft;
|
||||
}
|
||||
};
|
||||
left.addEventListener('scroll', onScroll);
|
||||
right.addEventListener('scroll', onScroll);
|
||||
});
|
||||
}
|
||||
|
||||
fileListToggle(startVisible: boolean): void {
|
||||
const hashTag = this.getHashTag();
|
||||
|
||||
const showBtn = this.targetElement.querySelector('.d2h-show') as HTMLElement;
|
||||
const hideBtn = this.targetElement.querySelector('.d2h-hide') as HTMLElement;
|
||||
const fileList = this.targetElement.querySelector('.d2h-file-list') as HTMLElement;
|
||||
|
||||
if (showBtn === null || hideBtn === null || fileList === null) return;
|
||||
|
||||
function show(): void {
|
||||
showBtn.style.display = 'none';
|
||||
hideBtn.style.display = 'inline';
|
||||
fileList.style.display = 'block';
|
||||
}
|
||||
|
||||
function hide(): void {
|
||||
showBtn.style.display = 'inline';
|
||||
hideBtn.style.display = 'none';
|
||||
fileList.style.display = 'none';
|
||||
}
|
||||
|
||||
showBtn.addEventListener('click', () => show());
|
||||
hideBtn.addEventListener('click', () => hide());
|
||||
|
||||
if (hashTag === 'files-summary-show') show();
|
||||
else if (hashTag === 'files-summary-hide') hide();
|
||||
else if (startVisible) show();
|
||||
else hide();
|
||||
}
|
||||
|
||||
highlightCode(): void {
|
||||
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 => {
|
||||
let oldLinesState: ICompiledMode;
|
||||
let newLinesState: ICompiledMode;
|
||||
|
||||
// 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 as HTMLElement;
|
||||
|
||||
if (lineParent === null || text === null) return;
|
||||
|
||||
const lineState = lineParent.className.indexOf('d2h-del') !== -1 ? oldLinesState : newLinesState;
|
||||
|
||||
const language = file.getAttribute('data-lang');
|
||||
const result =
|
||||
language && this.hljs.getLanguage(language)
|
||||
? this.hljs.highlight(language, text, true, lineState)
|
||||
: this.hljs.highlightAuto(text);
|
||||
|
||||
if (this.instanceOfIHighlightResult(result)) {
|
||||
if (lineParent.className.indexOf('d2h-del') !== -1) {
|
||||
oldLinesState = result.top;
|
||||
} else if (lineParent.className.indexOf('d2h-ins') !== -1) {
|
||||
newLinesState = result.top;
|
||||
} else {
|
||||
oldLinesState = result.top;
|
||||
newLinesState = result.top;
|
||||
}
|
||||
}
|
||||
|
||||
const originalStream = nodeStream(line);
|
||||
if (originalStream.length) {
|
||||
const resultNode = document.createElementNS('http://www.w3.org/1999/xhtml', 'div');
|
||||
resultNode.innerHTML = result.value;
|
||||
result.value = mergeStreams(originalStream, nodeStream(resultNode), text);
|
||||
}
|
||||
|
||||
line.classList.add('hljs');
|
||||
line.classList.add('result.language');
|
||||
line.innerHTML = result.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private instanceOfIHighlightResult(object: IHighlightResult | IAutoHighlightResult): object is IHighlightResult {
|
||||
return 'top' in object;
|
||||
}
|
||||
|
||||
private getHashTag(): string | null {
|
||||
const docUrl = document.URL;
|
||||
const hashTagIndex = docUrl.indexOf('#');
|
||||
|
||||
let hashTag = null;
|
||||
if (hashTagIndex !== -1) {
|
||||
hashTag = docUrl.substr(hashTagIndex + 1);
|
||||
}
|
||||
|
||||
return hashTag;
|
||||
}
|
||||
|
||||
private initSelection(): void {
|
||||
const body = document.getElementsByTagName('body')[0];
|
||||
const diffTable = body.getElementsByClassName('d2h-diff-table')[0];
|
||||
|
||||
diffTable.addEventListener('mousedown', event => {
|
||||
if (event === null || event.target === null) return;
|
||||
|
||||
const mouseEvent = event as MouseEvent;
|
||||
const target = mouseEvent.target as HTMLElement;
|
||||
const table = target.closest('.d2h-diff-table');
|
||||
|
||||
if (table !== null) {
|
||||
if (target.closest('.d2h-code-line,.d2h-code-side-line') !== null) {
|
||||
table.classList.remove('selecting-left');
|
||||
table.classList.add('selecting-right');
|
||||
this.currentSelectionColumnId = 1;
|
||||
} else if (target.closest('.d2h-code-linenumber,.d2h-code-side-linenumber') !== null) {
|
||||
table.classList.remove('selecting-right');
|
||||
table.classList.add('selecting-left');
|
||||
this.currentSelectionColumnId = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
diffTable.addEventListener('copy', event => {
|
||||
const clipboardEvent = event as ClipboardEvent;
|
||||
const clipboardData = clipboardEvent.clipboardData;
|
||||
const text = this.getSelectedText();
|
||||
|
||||
if (clipboardData === null || text === undefined) return;
|
||||
|
||||
clipboardData.setData('text', text);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
private getSelectedText(): string | undefined {
|
||||
const sel = window.getSelection();
|
||||
|
||||
if (sel === null) return;
|
||||
|
||||
const range = sel.getRangeAt(0);
|
||||
const doc = range.cloneContents();
|
||||
const nodes = doc.querySelectorAll('tr');
|
||||
const idx = this.currentSelectionColumnId;
|
||||
|
||||
let text = '';
|
||||
if (nodes.length === 0) {
|
||||
text = doc.textContent || '';
|
||||
} else {
|
||||
nodes.forEach((tr, i) => {
|
||||
const td = tr.cells[tr.cells.length === 1 ? 0 : idx];
|
||||
|
||||
if (td === undefined || td.textContent === null) return;
|
||||
|
||||
text += (i ? '\n' : '') + td.textContent.replace(/\r\n|\r|\n/g, '');
|
||||
});
|
||||
}
|
||||
|
||||
return text;
|
||||
}
|
||||
}
|
||||
12
src/ui/js/diff2html-ui-slim.ts
Normal file
12
src/ui/js/diff2html-ui-slim.ts
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
import { hljs } from './highlight.js-slim';
|
||||
|
||||
import { DiffFile } from '../../types';
|
||||
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
|
||||
|
||||
export class Diff2HtmlUI extends Diff2HtmlUIBase {
|
||||
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) {
|
||||
super(diffInput, target, config, hljs);
|
||||
}
|
||||
}
|
||||
|
||||
export { Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig };
|
||||
|
|
@ -1,223 +1,12 @@
|
|||
import HighlightJS from "highlight.js";
|
||||
import * as HighlightJSInternals from "./highlight.js-internals";
|
||||
import { html, Diff2HtmlConfig, defaultDiff2HtmlConfig } from "../../diff2html";
|
||||
import { DiffFile } from "../../types";
|
||||
import hljs from 'highlight.js';
|
||||
|
||||
export interface Diff2HtmlUIConfig extends Diff2HtmlConfig {
|
||||
synchronisedScroll?: boolean;
|
||||
highlight?: boolean;
|
||||
fileListToggle?: boolean;
|
||||
fileListStartVisible?: boolean;
|
||||
smartSelection?: boolean;
|
||||
}
|
||||
|
||||
export const defaultDiff2HtmlUIConfig = {
|
||||
...defaultDiff2HtmlConfig,
|
||||
synchronisedScroll: true,
|
||||
highlight: true,
|
||||
fileListToggle: true,
|
||||
fileListStartVisible: false,
|
||||
smartSelection: true
|
||||
};
|
||||
|
||||
export class Diff2HtmlUI {
|
||||
readonly config: typeof defaultDiff2HtmlUIConfig;
|
||||
readonly diffHtml: string;
|
||||
targetElement: HTMLElement;
|
||||
currentSelectionColumnId = -1;
|
||||
import { DiffFile } from '../../types';
|
||||
import { Diff2HtmlUI as Diff2HtmlUIBase, Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig } from './diff2html-ui-base';
|
||||
|
||||
export class Diff2HtmlUI extends Diff2HtmlUIBase {
|
||||
constructor(diffInput: string | DiffFile[], target: HTMLElement, config: Diff2HtmlUIConfig = {}) {
|
||||
this.config = { ...defaultDiff2HtmlUIConfig, ...config };
|
||||
this.diffHtml = html(diffInput, this.config);
|
||||
this.targetElement = target;
|
||||
}
|
||||
|
||||
draw(): void {
|
||||
this.targetElement.innerHTML = this.diffHtml;
|
||||
if (this.config.smartSelection) this.initSelection();
|
||||
if (this.config.synchronisedScroll) this.synchronisedScroll();
|
||||
if (this.config.highlight) this.highlightCode();
|
||||
if (this.config.fileListToggle) this.fileListToggle(this.config.fileListStartVisible);
|
||||
}
|
||||
|
||||
synchronisedScroll(): void {
|
||||
this.targetElement.querySelectorAll(".d2h-file-wrapper").forEach(wrapper => {
|
||||
const [left, right] = [].slice.call(wrapper.querySelectorAll(".d2h-file-side-diff")) as HTMLElement[];
|
||||
if (left === undefined || right === undefined) return;
|
||||
const onScroll = (event: Event): void => {
|
||||
if (event === null || event.target === null) return;
|
||||
if (event.target === left) {
|
||||
right.scrollTop = left.scrollTop;
|
||||
right.scrollLeft = left.scrollLeft;
|
||||
} else {
|
||||
left.scrollTop = right.scrollTop;
|
||||
left.scrollLeft = right.scrollLeft;
|
||||
}
|
||||
};
|
||||
left.addEventListener("scroll", onScroll);
|
||||
right.addEventListener("scroll", onScroll);
|
||||
});
|
||||
}
|
||||
|
||||
fileListToggle(startVisible: boolean): void {
|
||||
const hashTag = this.getHashTag();
|
||||
|
||||
const showBtn = this.targetElement.querySelector(".d2h-show") as HTMLElement;
|
||||
const hideBtn = this.targetElement.querySelector(".d2h-hide") as HTMLElement;
|
||||
const fileList = this.targetElement.querySelector(".d2h-file-list") as HTMLElement;
|
||||
|
||||
if (showBtn === null || hideBtn === null || fileList === null) return;
|
||||
|
||||
function show(): void {
|
||||
showBtn.style.display = "none";
|
||||
hideBtn.style.display = "inline";
|
||||
fileList.style.display = "block";
|
||||
}
|
||||
|
||||
function hide(): void {
|
||||
showBtn.style.display = "inline";
|
||||
hideBtn.style.display = "none";
|
||||
fileList.style.display = "none";
|
||||
}
|
||||
|
||||
showBtn.addEventListener("click", () => show());
|
||||
hideBtn.addEventListener("click", () => hide());
|
||||
|
||||
if (hashTag === "files-summary-show") show();
|
||||
else if (hashTag === "files-summary-hide") hide();
|
||||
else if (startVisible) show();
|
||||
else hide();
|
||||
}
|
||||
|
||||
highlightCode(): void {
|
||||
// Collect all the diff files and execute the highlight on their lines
|
||||
const files = this.targetElement.querySelectorAll(".d2h-file-wrapper");
|
||||
files.forEach(file => {
|
||||
let oldLinesState: HighlightJS.ICompiledMode;
|
||||
let newLinesState: HighlightJS.ICompiledMode;
|
||||
|
||||
// Collect all the code lines and execute the highlight on them
|
||||
const codeLines = file.querySelectorAll(".d2h-code-line-ctn");
|
||||
codeLines.forEach(line => {
|
||||
const text = line.textContent;
|
||||
const lineParent = line.parentNode as HTMLElement;
|
||||
|
||||
if (lineParent === null || text === null) return;
|
||||
|
||||
const lineState = lineParent.className.indexOf("d2h-del") !== -1 ? oldLinesState : newLinesState;
|
||||
|
||||
const language = file.getAttribute("data-lang");
|
||||
const result =
|
||||
language && HighlightJS.getLanguage(language)
|
||||
? HighlightJS.highlight(language, text, true, lineState)
|
||||
: HighlightJS.highlightAuto(text);
|
||||
|
||||
if (this.instanceOfIHighlightResult(result)) {
|
||||
if (lineParent.className.indexOf("d2h-del") !== -1) {
|
||||
oldLinesState = result.top;
|
||||
} else if (lineParent.className.indexOf("d2h-ins") !== -1) {
|
||||
newLinesState = result.top;
|
||||
} else {
|
||||
oldLinesState = result.top;
|
||||
newLinesState = result.top;
|
||||
}
|
||||
}
|
||||
|
||||
const originalStream = HighlightJSInternals.nodeStream(line);
|
||||
if (originalStream.length) {
|
||||
const resultNode = document.createElementNS("http://www.w3.org/1999/xhtml", "div");
|
||||
resultNode.innerHTML = result.value;
|
||||
result.value = HighlightJSInternals.mergeStreams(
|
||||
originalStream,
|
||||
HighlightJSInternals.nodeStream(resultNode),
|
||||
text
|
||||
);
|
||||
}
|
||||
|
||||
line.classList.add("hljs");
|
||||
line.classList.add("result.language");
|
||||
line.innerHTML = result.value;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
private instanceOfIHighlightResult(
|
||||
object: HighlightJS.IHighlightResult | HighlightJS.IAutoHighlightResult
|
||||
): object is HighlightJS.IHighlightResult {
|
||||
return "top" in object;
|
||||
}
|
||||
|
||||
private getHashTag(): string | null {
|
||||
const docUrl = document.URL;
|
||||
const hashTagIndex = docUrl.indexOf("#");
|
||||
|
||||
let hashTag = null;
|
||||
if (hashTagIndex !== -1) {
|
||||
hashTag = docUrl.substr(hashTagIndex + 1);
|
||||
}
|
||||
|
||||
return hashTag;
|
||||
}
|
||||
|
||||
private initSelection(): void {
|
||||
const body = document.getElementsByTagName("body")[0];
|
||||
const diffTable = body.getElementsByClassName("d2h-diff-table")[0];
|
||||
|
||||
diffTable.addEventListener("mousedown", event => {
|
||||
if (event === null || event.target === null) return;
|
||||
|
||||
const mouseEvent = event as MouseEvent;
|
||||
const target = mouseEvent.target as HTMLElement;
|
||||
const table = target.closest(".d2h-diff-table");
|
||||
|
||||
if (table !== null) {
|
||||
if (target.closest(".d2h-code-line,.d2h-code-side-line") !== null) {
|
||||
table.classList.remove("selecting-left");
|
||||
table.classList.add("selecting-right");
|
||||
this.currentSelectionColumnId = 1;
|
||||
} else if (target.closest(".d2h-code-linenumber,.d2h-code-side-linenumber") !== null) {
|
||||
table.classList.remove("selecting-right");
|
||||
table.classList.add("selecting-left");
|
||||
this.currentSelectionColumnId = 0;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
diffTable.addEventListener("copy", event => {
|
||||
const clipboardEvent = event as ClipboardEvent;
|
||||
const clipboardData = clipboardEvent.clipboardData;
|
||||
const text = this.getSelectedText();
|
||||
|
||||
if (clipboardData === null || text === undefined) return;
|
||||
|
||||
clipboardData.setData("text", text);
|
||||
event.preventDefault();
|
||||
});
|
||||
}
|
||||
|
||||
private getSelectedText(): string | undefined {
|
||||
const sel = window.getSelection();
|
||||
|
||||
if (sel === null) return;
|
||||
|
||||
const range = sel.getRangeAt(0);
|
||||
const doc = range.cloneContents();
|
||||
const nodes = doc.querySelectorAll("tr");
|
||||
const idx = this.currentSelectionColumnId;
|
||||
|
||||
let text = "";
|
||||
if (nodes.length === 0) {
|
||||
text = doc.textContent || "";
|
||||
} else {
|
||||
nodes.forEach((tr, i) => {
|
||||
const td = tr.cells[tr.cells.length === 1 ? 0 : idx];
|
||||
|
||||
if (td === undefined || td.textContent === null) return;
|
||||
|
||||
text += (i ? "\n" : "") + td.textContent.replace(/(?:\r\n|\r|\n)/g, "");
|
||||
});
|
||||
}
|
||||
|
||||
return text;
|
||||
super(diffInput, target, config, hljs);
|
||||
}
|
||||
}
|
||||
|
||||
export { Diff2HtmlUIConfig, defaultDiff2HtmlUIConfig };
|
||||
|
|
|
|||
|
|
@ -1,15 +1,15 @@
|
|||
/*
|
||||
* Copied from Highlight.js Private API
|
||||
* Will be removed when this part of the API is exposed
|
||||
* Adapted Highlight.js Internal APIs
|
||||
* Used to highlight selected html elements using context
|
||||
*/
|
||||
|
||||
/* Utility functions */
|
||||
|
||||
function escape(value: string): string {
|
||||
return value
|
||||
.replace(/&/gm, "&")
|
||||
.replace(/</gm, "<")
|
||||
.replace(/>/gm, ">");
|
||||
.replace(/&/gm, '&')
|
||||
.replace(/</gm, '<')
|
||||
.replace(/>/gm, '>');
|
||||
}
|
||||
|
||||
function tag(node: Node): string {
|
||||
|
|
@ -19,7 +19,7 @@ function tag(node: Node): string {
|
|||
/* Stream merging */
|
||||
|
||||
type NodeEvent = {
|
||||
event: "start" | "stop";
|
||||
event: 'start' | 'stop';
|
||||
offset: number;
|
||||
node: Node;
|
||||
};
|
||||
|
|
@ -33,9 +33,9 @@ export function nodeStream(node: Node): NodeEvent[] {
|
|||
offset += child.nodeValue.length;
|
||||
} else if (child.nodeType === 1) {
|
||||
result.push({
|
||||
event: "start",
|
||||
event: 'start',
|
||||
offset: offset,
|
||||
node: child
|
||||
node: child,
|
||||
});
|
||||
offset = nodeStream(child, offset);
|
||||
// Prevent void elements from having an end tag that would actually
|
||||
|
|
@ -43,9 +43,9 @@ export function nodeStream(node: Node): NodeEvent[] {
|
|||
// but we list only those realistically expected in code display.
|
||||
if (!tag(child).match(/br|hr|img|input/)) {
|
||||
result.push({
|
||||
event: "stop",
|
||||
event: 'stop',
|
||||
offset: offset,
|
||||
node: child
|
||||
node: child,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -60,7 +60,7 @@ export function nodeStream(node: Node): NodeEvent[] {
|
|||
|
||||
export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], value: string): string {
|
||||
let processed = 0;
|
||||
let result = "";
|
||||
let result = '';
|
||||
const nodeStack = [];
|
||||
|
||||
function selectStream(): NodeEvent[] {
|
||||
|
|
@ -84,22 +84,22 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
|
|||
return highlighted;
|
||||
... which is collapsed to:
|
||||
*/
|
||||
return highlighted[0].event === "start" ? original : highlighted;
|
||||
return highlighted[0].event === 'start' ? original : highlighted;
|
||||
}
|
||||
|
||||
function open(node: Node): void {
|
||||
const htmlNode = node as HTMLElement;
|
||||
result += `<${tag(node)} ${[].map
|
||||
.call(htmlNode.attributes, (attr: Attr) => `${attr.nodeName}="${escape(attr.value)}"`)
|
||||
.join(" ")}>`;
|
||||
.join(' ')}>`;
|
||||
}
|
||||
|
||||
function close(node: Node): void {
|
||||
result += "</" + tag(node) + ">";
|
||||
result += '</' + tag(node) + '>';
|
||||
}
|
||||
|
||||
function render(event: NodeEvent): void {
|
||||
(event.event === "start" ? open : close)(event.node);
|
||||
(event.event === 'start' ? open : close)(event.node);
|
||||
}
|
||||
|
||||
while (original.length || highlighted.length) {
|
||||
|
|
@ -120,7 +120,7 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
|
|||
} while (stream === original && stream.length && stream[0].offset === processed);
|
||||
nodeStack.reverse().forEach(open);
|
||||
} else {
|
||||
if (stream[0].event === "start") {
|
||||
if (stream[0].event === 'start') {
|
||||
nodeStack.push(stream[0].node);
|
||||
} else {
|
||||
nodeStack.pop();
|
||||
|
|
@ -130,5 +130,3 @@ export function mergeStreams(original: NodeEvent[], highlighted: NodeEvent[], va
|
|||
}
|
||||
return result + escape(value.substr(processed));
|
||||
}
|
||||
|
||||
/* **** Highlight.js Private API **** */
|
||||
69
src/ui/js/highlight.js-interface.ts
Normal file
69
src/ui/js/highlight.js-interface.ts
Normal file
|
|
@ -0,0 +1,69 @@
|
|||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
/* eslint-disable @typescript-eslint/interface-name-prefix */
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
|
||||
export interface HighlightJS {
|
||||
highlight(name: string, value: string, ignore_illegals?: boolean, continuation?: ICompiledMode): IHighlightResult;
|
||||
|
||||
highlightAuto(value: string, languageSubset?: string[]): IAutoHighlightResult;
|
||||
|
||||
getLanguage(name: string): IMode;
|
||||
}
|
||||
|
||||
export interface IAutoHighlightResult extends IHighlightResultBase {
|
||||
second_best?: IAutoHighlightResult;
|
||||
}
|
||||
|
||||
export interface IHighlightResultBase {
|
||||
relevance: number;
|
||||
language: string;
|
||||
value: string;
|
||||
}
|
||||
|
||||
export interface IHighlightResult extends IHighlightResultBase {
|
||||
top: ICompiledMode;
|
||||
}
|
||||
|
||||
export interface IMode extends IModeBase {
|
||||
keywords?: any;
|
||||
contains?: IMode[];
|
||||
}
|
||||
|
||||
// Reference:
|
||||
// https://github.com/isagalaev/highlight.js/blob/master/docs/reference.rst
|
||||
export interface IModeBase {
|
||||
className?: string;
|
||||
aliases?: string[];
|
||||
begin?: string | RegExp;
|
||||
end?: string | RegExp;
|
||||
case_insensitive?: boolean;
|
||||
beginKeyword?: string;
|
||||
endsWithParent?: boolean;
|
||||
lexems?: string;
|
||||
illegal?: string;
|
||||
excludeBegin?: boolean;
|
||||
excludeEnd?: boolean;
|
||||
returnBegin?: boolean;
|
||||
returnEnd?: boolean;
|
||||
starts?: string;
|
||||
subLanguage?: string;
|
||||
subLanguageMode?: string;
|
||||
relevance?: number;
|
||||
variants?: IMode[];
|
||||
}
|
||||
|
||||
export interface ICompiledMode extends IModeBase {
|
||||
compiled: boolean;
|
||||
contains?: ICompiledMode[];
|
||||
keywords?: Object;
|
||||
terminators: RegExp;
|
||||
terminator_end?: string;
|
||||
}
|
||||
|
||||
export interface IOptions {
|
||||
classPrefix?: string;
|
||||
tabReplace?: string;
|
||||
useBR?: boolean;
|
||||
languages?: string[];
|
||||
}
|
||||
203
src/ui/js/highlight.js-slim.ts
Normal file
203
src/ui/js/highlight.js-slim.ts
Normal file
|
|
@ -0,0 +1,203 @@
|
|||
import { HighlightJS } from './highlight.js-interface';
|
||||
|
||||
/* eslint-disable @typescript-eslint/camelcase */
|
||||
/* eslint-disable @typescript-eslint/no-var-requires */
|
||||
/* eslint-disable @typescript-eslint/interface-name-prefix */
|
||||
/* eslint-disable @typescript-eslint/ban-types */
|
||||
/* eslint-disable @typescript-eslint/no-explicit-any */
|
||||
|
||||
/*
|
||||
* Adapted Highlight.js External APIs
|
||||
* Used to avoid importing all the languages
|
||||
*/
|
||||
|
||||
// Require the highlight.js library without languages
|
||||
const highlightJS = require('highlight.js/lib/highlight.js');
|
||||
// Separately require languages
|
||||
// highlightJS.registerLanguage('1c', require('highlight.js/lib/languages/1c'));
|
||||
// highlightJS.registerLanguage('abnf', require('highlight.js/lib/languages/abnf'));
|
||||
// highlightJS.registerLanguage('accesslog', require('highlight.js/lib/languages/accesslog'));
|
||||
// highlightJS.registerLanguage('actionscript', require('highlight.js/lib/languages/actionscript'));
|
||||
// highlightJS.registerLanguage('ada', require('highlight.js/lib/languages/ada'));
|
||||
// highlightJS.registerLanguage('angelscript', require('highlight.js/lib/languages/angelscript'));
|
||||
// highlightJS.registerLanguage('apache', require('highlight.js/lib/languages/apache'));
|
||||
// highlightJS.registerLanguage('applescript', require('highlight.js/lib/languages/applescript'));
|
||||
// highlightJS.registerLanguage('arcade', require('highlight.js/lib/languages/arcade'));
|
||||
highlightJS.registerLanguage('cpp', require('highlight.js/lib/languages/cpp'));
|
||||
// highlightJS.registerLanguage('arduino', require('highlight.js/lib/languages/arduino'));
|
||||
// highlightJS.registerLanguage('armasm', require('highlight.js/lib/languages/armasm'));
|
||||
highlightJS.registerLanguage('xml', require('highlight.js/lib/languages/xml'));
|
||||
// highlightJS.registerLanguage('asciidoc', require('highlight.js/lib/languages/asciidoc'));
|
||||
// highlightJS.registerLanguage('aspectj', require('highlight.js/lib/languages/aspectj'));
|
||||
// highlightJS.registerLanguage('autohotkey', require('highlight.js/lib/languages/autohotkey'));
|
||||
// highlightJS.registerLanguage('autoit', require('highlight.js/lib/languages/autoit'));
|
||||
// highlightJS.registerLanguage('avrasm', require('highlight.js/lib/languages/avrasm'));
|
||||
highlightJS.registerLanguage('awk', require('highlight.js/lib/languages/awk'));
|
||||
// highlightJS.registerLanguage('axapta', require('highlight.js/lib/languages/axapta'));
|
||||
highlightJS.registerLanguage('bash', require('highlight.js/lib/languages/bash'));
|
||||
// highlightJS.registerLanguage('basic', require('highlight.js/lib/languages/basic'));
|
||||
// highlightJS.registerLanguage('bnf', require('highlight.js/lib/languages/bnf'));
|
||||
// highlightJS.registerLanguage('brainfuck', require('highlight.js/lib/languages/brainfuck'));
|
||||
// highlightJS.registerLanguage('cal', require('highlight.js/lib/languages/cal'));
|
||||
// highlightJS.registerLanguage('capnproto', require('highlight.js/lib/languages/capnproto'));
|
||||
// highlightJS.registerLanguage('ceylon', require('highlight.js/lib/languages/ceylon'));
|
||||
// highlightJS.registerLanguage('clean', require('highlight.js/lib/languages/clean'));
|
||||
highlightJS.registerLanguage('clojure', require('highlight.js/lib/languages/clojure'));
|
||||
highlightJS.registerLanguage('clojure-repl', require('highlight.js/lib/languages/clojure-repl'));
|
||||
highlightJS.registerLanguage('cmake', require('highlight.js/lib/languages/cmake'));
|
||||
highlightJS.registerLanguage('coffeescript', require('highlight.js/lib/languages/coffeescript'));
|
||||
// highlightJS.registerLanguage('coq', require('highlight.js/lib/languages/coq'));
|
||||
// highlightJS.registerLanguage('cos', require('highlight.js/lib/languages/cos'));
|
||||
// highlightJS.registerLanguage('crmsh', require('highlight.js/lib/languages/crmsh'));
|
||||
highlightJS.registerLanguage('crystal', require('highlight.js/lib/languages/crystal'));
|
||||
highlightJS.registerLanguage('cs', require('highlight.js/lib/languages/cs'));
|
||||
highlightJS.registerLanguage('csp', require('highlight.js/lib/languages/csp'));
|
||||
highlightJS.registerLanguage('css', require('highlight.js/lib/languages/css'));
|
||||
highlightJS.registerLanguage('d', require('highlight.js/lib/languages/d'));
|
||||
highlightJS.registerLanguage('markdown', require('highlight.js/lib/languages/markdown'));
|
||||
highlightJS.registerLanguage('dart', require('highlight.js/lib/languages/dart'));
|
||||
// highlightJS.registerLanguage('delphi', require('highlight.js/lib/languages/delphi'));
|
||||
highlightJS.registerLanguage('diff', require('highlight.js/lib/languages/diff'));
|
||||
highlightJS.registerLanguage('django', require('highlight.js/lib/languages/django'));
|
||||
// highlightJS.registerLanguage('dns', require('highlight.js/lib/languages/dns'));
|
||||
highlightJS.registerLanguage('dockerfile', require('highlight.js/lib/languages/dockerfile'));
|
||||
// highlightJS.registerLanguage('dos', require('highlight.js/lib/languages/dos'));
|
||||
// highlightJS.registerLanguage('dsconfig', require('highlight.js/lib/languages/dsconfig'));
|
||||
// highlightJS.registerLanguage('dts', require('highlight.js/lib/languages/dts'));
|
||||
// highlightJS.registerLanguage('dust', require('highlight.js/lib/languages/dust'));
|
||||
// highlightJS.registerLanguage('ebnf', require('highlight.js/lib/languages/ebnf'));
|
||||
highlightJS.registerLanguage('elixir', require('highlight.js/lib/languages/elixir'));
|
||||
highlightJS.registerLanguage('elm', require('highlight.js/lib/languages/elm'));
|
||||
highlightJS.registerLanguage('ruby', require('highlight.js/lib/languages/ruby'));
|
||||
highlightJS.registerLanguage('erb', require('highlight.js/lib/languages/erb'));
|
||||
highlightJS.registerLanguage('erlang-repl', require('highlight.js/lib/languages/erlang-repl'));
|
||||
highlightJS.registerLanguage('erlang', require('highlight.js/lib/languages/erlang'));
|
||||
highlightJS.registerLanguage('excel', require('highlight.js/lib/languages/excel'));
|
||||
// highlightJS.registerLanguage('fix', require('highlight.js/lib/languages/fix'));
|
||||
// highlightJS.registerLanguage('flix', require('highlight.js/lib/languages/flix'));
|
||||
// highlightJS.registerLanguage('fortran', require('highlight.js/lib/languages/fortran'));
|
||||
highlightJS.registerLanguage('fsharp', require('highlight.js/lib/languages/fsharp'));
|
||||
// highlightJS.registerLanguage('gams', require('highlight.js/lib/languages/gams'));
|
||||
// highlightJS.registerLanguage('gauss', require('highlight.js/lib/languages/gauss'));
|
||||
// highlightJS.registerLanguage('gcode', require('highlight.js/lib/languages/gcode'));
|
||||
// highlightJS.registerLanguage('gherkin', require('highlight.js/lib/languages/gherkin'));
|
||||
// highlightJS.registerLanguage('glsl', require('highlight.js/lib/languages/glsl'));
|
||||
// highlightJS.registerLanguage('gml', require('highlight.js/lib/languages/gml'));
|
||||
highlightJS.registerLanguage('go', require('highlight.js/lib/languages/go'));
|
||||
// highlightJS.registerLanguage('golo', require('highlight.js/lib/languages/golo'));
|
||||
highlightJS.registerLanguage('gradle', require('highlight.js/lib/languages/gradle'));
|
||||
highlightJS.registerLanguage('groovy', require('highlight.js/lib/languages/groovy'));
|
||||
// highlightJS.registerLanguage('haml', require('highlight.js/lib/languages/haml'));
|
||||
highlightJS.registerLanguage('handlebars', require('highlight.js/lib/languages/handlebars'));
|
||||
highlightJS.registerLanguage('haskell', require('highlight.js/lib/languages/haskell'));
|
||||
// highlightJS.registerLanguage('haxe', require('highlight.js/lib/languages/haxe'));
|
||||
// highlightJS.registerLanguage('hsp', require('highlight.js/lib/languages/hsp'));
|
||||
highlightJS.registerLanguage('htmlbars', require('highlight.js/lib/languages/htmlbars'));
|
||||
highlightJS.registerLanguage('http', require('highlight.js/lib/languages/http'));
|
||||
// highlightJS.registerLanguage('hy', require('highlight.js/lib/languages/hy'));
|
||||
// highlightJS.registerLanguage('inform7', require('highlight.js/lib/languages/inform7'));
|
||||
highlightJS.registerLanguage('ini', require('highlight.js/lib/languages/ini'));
|
||||
// highlightJS.registerLanguage('irpf90', require('highlight.js/lib/languages/irpf90'));
|
||||
// highlightJS.registerLanguage('isbl', require('highlight.js/lib/languages/isbl'));
|
||||
highlightJS.registerLanguage('java', require('highlight.js/lib/languages/java'));
|
||||
highlightJS.registerLanguage('javascript', require('highlight.js/lib/languages/javascript'));
|
||||
// highlightJS.registerLanguage('jboss-cli', require('highlight.js/lib/languages/jboss-cli'));
|
||||
highlightJS.registerLanguage('json', require('highlight.js/lib/languages/json'));
|
||||
highlightJS.registerLanguage('julia', require('highlight.js/lib/languages/julia'));
|
||||
highlightJS.registerLanguage('julia-repl', require('highlight.js/lib/languages/julia-repl'));
|
||||
highlightJS.registerLanguage('kotlin', require('highlight.js/lib/languages/kotlin'));
|
||||
// highlightJS.registerLanguage('lasso', require('highlight.js/lib/languages/lasso'));
|
||||
// highlightJS.registerLanguage('ldif', require('highlight.js/lib/languages/ldif'));
|
||||
// highlightJS.registerLanguage('leaf', require('highlight.js/lib/languages/leaf'));
|
||||
highlightJS.registerLanguage('less', require('highlight.js/lib/languages/less'));
|
||||
highlightJS.registerLanguage('lisp', require('highlight.js/lib/languages/lisp'));
|
||||
// highlightJS.registerLanguage('livecodeserver', require('highlight.js/lib/languages/livecodeserver'));
|
||||
// highlightJS.registerLanguage('livescript', require('highlight.js/lib/languages/livescript'));
|
||||
highlightJS.registerLanguage('llvm', require('highlight.js/lib/languages/llvm'));
|
||||
// highlightJS.registerLanguage('lsl', require('highlight.js/lib/languages/lsl'));
|
||||
highlightJS.registerLanguage('lua', require('highlight.js/lib/languages/lua'));
|
||||
highlightJS.registerLanguage('makefile', require('highlight.js/lib/languages/makefile'));
|
||||
highlightJS.registerLanguage('mathematica', require('highlight.js/lib/languages/mathematica'));
|
||||
highlightJS.registerLanguage('matlab', require('highlight.js/lib/languages/matlab'));
|
||||
// highlightJS.registerLanguage('maxima', require('highlight.js/lib/languages/maxima'));
|
||||
// highlightJS.registerLanguage('mel', require('highlight.js/lib/languages/mel'));
|
||||
// highlightJS.registerLanguage('mercury', require('highlight.js/lib/languages/mercury'));
|
||||
// highlightJS.registerLanguage('mipsasm', require('highlight.js/lib/languages/mipsasm'));
|
||||
// highlightJS.registerLanguage('mizar', require('highlight.js/lib/languages/mizar'));
|
||||
highlightJS.registerLanguage('perl', require('highlight.js/lib/languages/perl'));
|
||||
// highlightJS.registerLanguage('mojolicious', require('highlight.js/lib/languages/mojolicious'));
|
||||
// highlightJS.registerLanguage('monkey', require('highlight.js/lib/languages/monkey'));
|
||||
// highlightJS.registerLanguage('moonscript', require('highlight.js/lib/languages/moonscript'));
|
||||
// highlightJS.registerLanguage('n1ql', require('highlight.js/lib/languages/n1ql'));
|
||||
highlightJS.registerLanguage('nginx', require('highlight.js/lib/languages/nginx'));
|
||||
// highlightJS.registerLanguage('nimrod', require('highlight.js/lib/languages/nimrod'));
|
||||
highlightJS.registerLanguage('nix', require('highlight.js/lib/languages/nix'));
|
||||
// highlightJS.registerLanguage('nsis', require('highlight.js/lib/languages/nsis'));
|
||||
highlightJS.registerLanguage('objectivec', require('highlight.js/lib/languages/objectivec'));
|
||||
highlightJS.registerLanguage('ocaml', require('highlight.js/lib/languages/ocaml'));
|
||||
// highlightJS.registerLanguage('openscad', require('highlight.js/lib/languages/openscad'));
|
||||
// highlightJS.registerLanguage('oxygene', require('highlight.js/lib/languages/oxygene'));
|
||||
// highlightJS.registerLanguage('parser3', require('highlight.js/lib/languages/parser3'));
|
||||
// highlightJS.registerLanguage('pf', require('highlight.js/lib/languages/pf'));
|
||||
highlightJS.registerLanguage('pgsql', require('highlight.js/lib/languages/pgsql'));
|
||||
highlightJS.registerLanguage('php', require('highlight.js/lib/languages/php'));
|
||||
highlightJS.registerLanguage('plaintext', require('highlight.js/lib/languages/plaintext'));
|
||||
// highlightJS.registerLanguage('pony', require('highlight.js/lib/languages/pony'));
|
||||
highlightJS.registerLanguage('powershell', require('highlight.js/lib/languages/powershell'));
|
||||
// highlightJS.registerLanguage('processing', require('highlight.js/lib/languages/processing'));
|
||||
// highlightJS.registerLanguage('profile', require('highlight.js/lib/languages/profile'));
|
||||
// highlightJS.registerLanguage('prolog', require('highlight.js/lib/languages/prolog'));
|
||||
highlightJS.registerLanguage('properties', require('highlight.js/lib/languages/properties'));
|
||||
highlightJS.registerLanguage('protobuf', require('highlight.js/lib/languages/protobuf'));
|
||||
highlightJS.registerLanguage('puppet', require('highlight.js/lib/languages/puppet'));
|
||||
// highlightJS.registerLanguage('purebasic', require('highlight.js/lib/languages/purebasic'));
|
||||
highlightJS.registerLanguage('python', require('highlight.js/lib/languages/python'));
|
||||
// highlightJS.registerLanguage('q', require('highlight.js/lib/languages/q'));
|
||||
// highlightJS.registerLanguage('qml', require('highlight.js/lib/languages/qml'));
|
||||
highlightJS.registerLanguage('r', require('highlight.js/lib/languages/r'));
|
||||
highlightJS.registerLanguage('reasonml', require('highlight.js/lib/languages/reasonml'));
|
||||
// highlightJS.registerLanguage('rib', require('highlight.js/lib/languages/rib'));
|
||||
// highlightJS.registerLanguage('roboconf', require('highlight.js/lib/languages/roboconf'));
|
||||
// highlightJS.registerLanguage('routeros', require('highlight.js/lib/languages/routeros'));
|
||||
// highlightJS.registerLanguage('rsl', require('highlight.js/lib/languages/rsl'));
|
||||
// highlightJS.registerLanguage('ruleslanguage', require('highlight.js/lib/languages/ruleslanguage'));
|
||||
highlightJS.registerLanguage('rust', require('highlight.js/lib/languages/rust'));
|
||||
// highlightJS.registerLanguage('sas', require('highlight.js/lib/languages/sas'));
|
||||
highlightJS.registerLanguage('scala', require('highlight.js/lib/languages/scala'));
|
||||
highlightJS.registerLanguage('scheme', require('highlight.js/lib/languages/scheme'));
|
||||
// highlightJS.registerLanguage('scilab', require('highlight.js/lib/languages/scilab'));
|
||||
highlightJS.registerLanguage('scss', require('highlight.js/lib/languages/scss'));
|
||||
highlightJS.registerLanguage('shell', require('highlight.js/lib/languages/shell'));
|
||||
// highlightJS.registerLanguage('smali', require('highlight.js/lib/languages/smali'));
|
||||
// highlightJS.registerLanguage('smalltalk', require('highlight.js/lib/languages/smalltalk'));
|
||||
// highlightJS.registerLanguage('sml', require('highlight.js/lib/languages/sml'));
|
||||
// highlightJS.registerLanguage('sqf', require('highlight.js/lib/languages/sqf'));
|
||||
highlightJS.registerLanguage('sql', require('highlight.js/lib/languages/sql'));
|
||||
// highlightJS.registerLanguage('stan', require('highlight.js/lib/languages/stan'));
|
||||
// highlightJS.registerLanguage('stata', require('highlight.js/lib/languages/stata'));
|
||||
// highlightJS.registerLanguage('step21', require('highlight.js/lib/languages/step21'));
|
||||
highlightJS.registerLanguage('stylus', require('highlight.js/lib/languages/stylus'));
|
||||
// highlightJS.registerLanguage('subunit', require('highlight.js/lib/languages/subunit'));
|
||||
highlightJS.registerLanguage('swift', require('highlight.js/lib/languages/swift'));
|
||||
// highlightJS.registerLanguage('taggerscript', require('highlight.js/lib/languages/taggerscript'));
|
||||
highlightJS.registerLanguage('yaml', require('highlight.js/lib/languages/yaml'));
|
||||
// highlightJS.registerLanguage('tap', require('highlight.js/lib/languages/tap'));
|
||||
// highlightJS.registerLanguage('tcl', require('highlight.js/lib/languages/tcl'));
|
||||
highlightJS.registerLanguage('tex', require('highlight.js/lib/languages/tex'));
|
||||
// highlightJS.registerLanguage('thrift', require('highlight.js/lib/languages/thrift'));
|
||||
// highlightJS.registerLanguage('tp', require('highlight.js/lib/languages/tp'));
|
||||
// highlightJS.registerLanguage('twig', require('highlight.js/lib/languages/twig'));
|
||||
highlightJS.registerLanguage('typescript', require('highlight.js/lib/languages/typescript'));
|
||||
// highlightJS.registerLanguage('vala', require('highlight.js/lib/languages/vala'));
|
||||
// highlightJS.registerLanguage('vbnet', require('highlight.js/lib/languages/vbnet'));
|
||||
// highlightJS.registerLanguage('vbscript', require('highlight.js/lib/languages/vbscript'));
|
||||
// highlightJS.registerLanguage('vbscript-html', require('highlight.js/lib/languages/vbscript-html'));
|
||||
// highlightJS.registerLanguage('verilog', require('highlight.js/lib/languages/verilog'));
|
||||
// highlightJS.registerLanguage('vhdl', require('highlight.js/lib/languages/vhdl'));
|
||||
highlightJS.registerLanguage('vim', require('highlight.js/lib/languages/vim'));
|
||||
// highlightJS.registerLanguage('x86asm', require('highlight.js/lib/languages/x86asm'));
|
||||
// highlightJS.registerLanguage('xl', require('highlight.js/lib/languages/xl'));
|
||||
// highlightJS.registerLanguage('xquery', require('highlight.js/lib/languages/xquery'));
|
||||
// highlightJS.registerLanguage('zephir', require('highlight.js/lib/languages/zephir'));
|
||||
|
||||
export const hljs: HighlightJS = highlightJS as HighlightJS;
|
||||
38
src/utils.ts
38
src/utils.ts
|
|
@ -1,40 +1,40 @@
|
|||
const specials = [
|
||||
// Order matters for these
|
||||
"-",
|
||||
"[",
|
||||
"]",
|
||||
'-',
|
||||
'[',
|
||||
']',
|
||||
// Order doesn't matter for any of these
|
||||
"/",
|
||||
"{",
|
||||
"}",
|
||||
"(",
|
||||
")",
|
||||
"*",
|
||||
"+",
|
||||
"?",
|
||||
".",
|
||||
"\\",
|
||||
"^",
|
||||
"$",
|
||||
"|"
|
||||
'/',
|
||||
'{',
|
||||
'}',
|
||||
'(',
|
||||
')',
|
||||
'*',
|
||||
'+',
|
||||
'?',
|
||||
'.',
|
||||
'\\',
|
||||
'^',
|
||||
'$',
|
||||
'|',
|
||||
];
|
||||
|
||||
// All characters will be escaped with '\'
|
||||
// even though only some strictly require it when inside of []
|
||||
const regex = RegExp("[" + specials.join("\\") + "]", "g");
|
||||
const regex = RegExp('[' + specials.join('\\') + ']', 'g');
|
||||
|
||||
/**
|
||||
* Escapes all required characters for safe usage inside a RegExp
|
||||
*/
|
||||
export function escapeForRegExp(str: string): string {
|
||||
return str.replace(regex, "\\$&");
|
||||
return str.replace(regex, '\\$&');
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts all '\' in @path to unix style '/'
|
||||
*/
|
||||
export function unifyPath(path: string): string {
|
||||
return path ? path.replace(/\\/g, "/") : path;
|
||||
return path ? path.replace(/\\/g, '/') : path;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
2
typings/merge.d.ts
vendored
2
typings/merge.d.ts
vendored
|
|
@ -1,3 +1,3 @@
|
|||
declare module "merge" {
|
||||
declare module 'merge' {
|
||||
export function recursive(clone: boolean, ...items: object[]): object;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,60 +1,61 @@
|
|||
import path from "path";
|
||||
import path from 'path';
|
||||
|
||||
import webpack from "webpack";
|
||||
|
||||
const minimize = process.env.WEBPACK_MINIFY === "true";
|
||||
import webpack from 'webpack';
|
||||
|
||||
const diff2htmlBrowserConfig: webpack.Configuration = {
|
||||
mode: "production",
|
||||
optimization: { minimize: minimize },
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: "ts-loader",
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".tsx", ".ts", ".jsx", ".js"]
|
||||
extensions: ['.tsx', '.ts', '.jsx', '.js'],
|
||||
},
|
||||
entry: "./src/diff2html.ts",
|
||||
entry: './src/diff2html.ts',
|
||||
output: {
|
||||
path: path.resolve(__dirname, "bundles/js"),
|
||||
libraryTarget: "umd",
|
||||
globalObject: "this",
|
||||
library: "Diff2Html",
|
||||
filename: `diff2html${minimize ? ".min" : ""}.js`,
|
||||
umdNamedDefine: true
|
||||
}
|
||||
path: path.resolve(__dirname, 'bundles/js'),
|
||||
libraryTarget: 'umd',
|
||||
globalObject: 'this',
|
||||
library: 'Diff2Html',
|
||||
filename: 'diff2html.min.js',
|
||||
umdNamedDefine: true,
|
||||
},
|
||||
};
|
||||
|
||||
const diff2htmlUIBrowserConfig: webpack.Configuration = {
|
||||
mode: "production",
|
||||
optimization: { minimize: minimize },
|
||||
function diff2htmlUIBrowserConfig(entrypointName: string): webpack.Configuration {
|
||||
return {
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: "ts-loader",
|
||||
exclude: /node_modules/
|
||||
}
|
||||
]
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
],
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".tsx", ".ts", ".jsx", ".js"]
|
||||
extensions: ['.tsx', '.ts', '.jsx', '.js'],
|
||||
},
|
||||
entry: "./src/ui/js/diff2html-ui.ts",
|
||||
entry: `./src/ui/js/${entrypointName}.ts`,
|
||||
output: {
|
||||
path: path.resolve(__dirname, "bundles/js"),
|
||||
libraryTarget: "umd",
|
||||
globalObject: "this",
|
||||
filename: `diff2html-ui${minimize ? ".min" : ""}.js`,
|
||||
umdNamedDefine: true
|
||||
}
|
||||
};
|
||||
path: path.resolve(__dirname, 'bundles/js'),
|
||||
libraryTarget: 'umd',
|
||||
globalObject: 'this',
|
||||
filename: `${entrypointName}.min.js`,
|
||||
umdNamedDefine: true,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
const config: webpack.Configuration[] = [diff2htmlBrowserConfig, diff2htmlUIBrowserConfig];
|
||||
const config: webpack.Configuration[] = [
|
||||
diff2htmlBrowserConfig,
|
||||
diff2htmlUIBrowserConfig('diff2html-ui'),
|
||||
diff2htmlUIBrowserConfig('diff2html-ui-slim'),
|
||||
diff2htmlUIBrowserConfig('diff2html-ui-base'),
|
||||
];
|
||||
|
||||
export default config;
|
||||
|
|
|
|||
|
|
@ -1,140 +1,116 @@
|
|||
import path from "path";
|
||||
import path from 'path';
|
||||
|
||||
import webpack from "webpack";
|
||||
import { Plugin } from "postcss";
|
||||
import HtmlWebpackPlugin from "html-webpack-plugin";
|
||||
import MiniCssExtractPlugin from "mini-css-extract-plugin";
|
||||
import autoprefixer from "autoprefixer";
|
||||
import CopyWebpackPlugin from "copy-webpack-plugin";
|
||||
import webpack from 'webpack';
|
||||
import HtmlWebpackPlugin from 'html-webpack-plugin';
|
||||
import MiniCssExtractPlugin from 'mini-css-extract-plugin';
|
||||
import CopyWebpackPlugin from 'copy-webpack-plugin';
|
||||
|
||||
const isDevelopment = process.env.NODE_ENV !== "production";
|
||||
const minimize = process.env.WEBPACK_MINIFY === "true";
|
||||
|
||||
const pages = ["index", "demo"];
|
||||
const pages = ['index', 'demo'];
|
||||
|
||||
const config: webpack.Configuration[] = pages.map(page => {
|
||||
return {
|
||||
devServer: {
|
||||
port: 3000,
|
||||
open: true,
|
||||
contentBase: path.join(__dirname, "./website")
|
||||
contentBase: path.join(__dirname, './website'),
|
||||
},
|
||||
entry: {
|
||||
[page]: `./website/templates/pages/${page}/${page}.ts`
|
||||
[page]: `./website/templates/pages/${page}/${page}.ts`,
|
||||
},
|
||||
output: {
|
||||
path: path.resolve(__dirname, "./docs")
|
||||
path: path.resolve(__dirname, './docs'),
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".tsx", ".ts", ".jsx", ".js"]
|
||||
extensions: ['.tsx', '.ts', '.jsx', '.js'],
|
||||
},
|
||||
optimization: { minimize },
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.tsx?$/,
|
||||
use: "ts-loader",
|
||||
exclude: /node_modules/
|
||||
use: 'ts-loader',
|
||||
exclude: /node_modules/,
|
||||
},
|
||||
{
|
||||
test: /\.handlebars$/,
|
||||
loader: "handlebars-loader",
|
||||
loader: 'handlebars-loader',
|
||||
options: {
|
||||
precompileOptions: {
|
||||
knownHelpersOnly: false
|
||||
knownHelpersOnly: false,
|
||||
},
|
||||
helperDirs: [path.join(__dirname, 'website/templates/helpers')],
|
||||
partialDirs: [path.join(__dirname, 'website/templates')],
|
||||
},
|
||||
helperDirs: [path.join(__dirname, "website/templates/helpers")],
|
||||
partialDirs: [path.join(__dirname, "website/templates")]
|
||||
}
|
||||
},
|
||||
{
|
||||
test: /\.(css)$/,
|
||||
use: [
|
||||
MiniCssExtractPlugin.loader,
|
||||
{
|
||||
loader: "css-loader",
|
||||
options: {
|
||||
sourceMap: isDevelopment
|
||||
}
|
||||
},
|
||||
{
|
||||
loader: "postcss-loader",
|
||||
options: {
|
||||
autoprefixer: {
|
||||
browsers: ["last 2 versions"]
|
||||
},
|
||||
sourceMap: isDevelopment,
|
||||
plugins: (): Plugin<object>[] => [autoprefixer]
|
||||
}
|
||||
}
|
||||
]
|
||||
use: [MiniCssExtractPlugin.loader, { loader: 'css-loader', options: { importLoaders: 1 } }, 'postcss-loader'],
|
||||
},
|
||||
{
|
||||
test: /\.(html)$/,
|
||||
use: {
|
||||
loader: "html-loader",
|
||||
loader: 'html-loader',
|
||||
options: {
|
||||
attrs: ["img:src"]
|
||||
}
|
||||
}
|
||||
attrs: ['img:src'],
|
||||
},
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.woff(2)?(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
test: /\.woff(2)?(\?v=\d\.\d\.\d)?$/,
|
||||
use: [
|
||||
{
|
||||
loader: "url-loader",
|
||||
loader: 'url-loader',
|
||||
options: {
|
||||
limit: 1000,
|
||||
mimetype: "application/font-woff"
|
||||
}
|
||||
}
|
||||
]
|
||||
mimetype: 'application/font-woff',
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.(ttf|eot|svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/,
|
||||
loader: "file-loader"
|
||||
test: /\.(ttf|eot|svg)(\?v=\d\.\d\.\d)?$/,
|
||||
loader: 'file-loader',
|
||||
},
|
||||
{
|
||||
test: /\.(jpeg|jpg|png|gif)$/,
|
||||
use: [
|
||||
{
|
||||
loader: "file-loader",
|
||||
loader: 'file-loader',
|
||||
options: {
|
||||
name: "[name].[ext]",
|
||||
outputPath: "images/",
|
||||
useRelativePath: true
|
||||
}
|
||||
name: '[name].[ext]',
|
||||
outputPath: 'images/',
|
||||
useRelativePath: true,
|
||||
},
|
||||
},
|
||||
{
|
||||
loader: "image-webpack-loader",
|
||||
loader: 'image-webpack-loader',
|
||||
options: {
|
||||
mozjpeg: {
|
||||
progressive: true,
|
||||
quality: 65
|
||||
quality: 65,
|
||||
},
|
||||
optipng: {
|
||||
enabled: true
|
||||
enabled: true,
|
||||
},
|
||||
pngquant: {
|
||||
quality: [0.65, 0.9],
|
||||
speed: 4
|
||||
speed: 4,
|
||||
},
|
||||
gifsicle: {
|
||||
interlaced: false
|
||||
interlaced: false,
|
||||
},
|
||||
webp: {
|
||||
quality: 75
|
||||
}
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
quality: 75,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
],
|
||||
},
|
||||
plugins: [
|
||||
new MiniCssExtractPlugin({
|
||||
filename: "[name].css",
|
||||
chunkFilename: "[id].css"
|
||||
filename: '[name].css',
|
||||
chunkFilename: '[id].css',
|
||||
}),
|
||||
new HtmlWebpackPlugin({
|
||||
hash: true,
|
||||
|
|
@ -142,7 +118,7 @@ const config: webpack.Configuration[] = pages.map(page => {
|
|||
title: `${page} page`,
|
||||
filename: `${page}.html`,
|
||||
template: `./website/templates/pages/${page}/${page}.handlebars`,
|
||||
minify: !isDevelopment && {
|
||||
minify: {
|
||||
html5: true,
|
||||
collapseWhitespace: true,
|
||||
caseSensitive: true,
|
||||
|
|
@ -155,15 +131,15 @@ const config: webpack.Configuration[] = pages.map(page => {
|
|||
keepClosingSlash: true,
|
||||
minifyJS: true,
|
||||
minifyCSS: true,
|
||||
minifyURLs: true
|
||||
}
|
||||
minifyURLs: true,
|
||||
},
|
||||
}),
|
||||
new CopyWebpackPlugin([
|
||||
{ from: "website/favicon.ico", to: "favicon.ico" },
|
||||
{ from: "website/robots.txt", to: "robots.txt" },
|
||||
{ from: "website/sitemap.xml", to: "sitemap.xml" }
|
||||
])
|
||||
]
|
||||
{ from: 'website/favicon.ico', to: 'favicon.ico' },
|
||||
{ from: 'website/robots.txt', to: 'robots.txt' },
|
||||
{ from: 'website/sitemap.xml', to: 'sitemap.xml' },
|
||||
]),
|
||||
],
|
||||
};
|
||||
});
|
||||
|
||||
|
|
|
|||
140
website/main.css
140
website/main.css
|
|
@ -17,11 +17,11 @@
|
|||
}
|
||||
|
||||
.m-b-md {
|
||||
margin-bottom: 23px !important
|
||||
margin-bottom: 23px !important;
|
||||
}
|
||||
|
||||
.p-t {
|
||||
padding-top: 15px !important
|
||||
padding-top: 15px !important;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
|
@ -34,8 +34,8 @@
|
|||
.btn {
|
||||
display: inline-block;
|
||||
color: #fff;
|
||||
background: #26A65B;
|
||||
font-weight: 400
|
||||
background: #26a65b;
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
.btn:hover {
|
||||
|
|
@ -67,19 +67,19 @@
|
|||
padding: 40px 0;
|
||||
text-align: center;
|
||||
font-size: 14px;
|
||||
border-top: 1px solid #dcdfe4
|
||||
border-top: 1px solid #dcdfe4;
|
||||
}
|
||||
|
||||
.footer p {
|
||||
margin-bottom: 5px
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.footer a {
|
||||
color: #26A65B;
|
||||
color: #26a65b;
|
||||
}
|
||||
|
||||
.container a {
|
||||
color: #26A65B;
|
||||
color: #26a65b;
|
||||
}
|
||||
|
||||
.container a.btn {
|
||||
|
|
@ -87,11 +87,11 @@
|
|||
}
|
||||
|
||||
.footer-list-item {
|
||||
display: inline-block
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.footer-list-item:not(:last-child):after {
|
||||
content: "\b7"
|
||||
content: '\b7';
|
||||
}
|
||||
|
||||
.footer > ul {
|
||||
|
|
@ -116,7 +116,7 @@
|
|||
}
|
||||
|
||||
.row-bordered {
|
||||
position: relative
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.row-bordered:before {
|
||||
|
|
@ -129,14 +129,14 @@
|
|||
margin-left: -40%;
|
||||
height: 1px;
|
||||
background: -webkit-radial-gradient(ellipse at center, rgba(0, 0, 0, 0.2) 0, rgba(255, 255, 255, 0) 75%);
|
||||
background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.2) 0, rgba(255, 255, 255, 0) 75%)
|
||||
background: radial-gradient(ellipse at center, rgba(0, 0, 0, 0.2) 0, rgba(255, 255, 255, 0) 75%);
|
||||
}
|
||||
|
||||
.hero {
|
||||
position: relative;
|
||||
text-align: center;
|
||||
padding: 80px 0;
|
||||
border-bottom: 1px solid #dcdfe4
|
||||
border-bottom: 1px solid #dcdfe4;
|
||||
}
|
||||
|
||||
.hero-booticon {
|
||||
|
|
@ -159,7 +159,7 @@
|
|||
}
|
||||
|
||||
.hero-homepage > .btn {
|
||||
margin-top: 20px
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.swag-line:before {
|
||||
|
|
@ -171,9 +171,9 @@
|
|||
right: 0;
|
||||
height: 5px;
|
||||
z-index: 2;
|
||||
background-color: #26A65B;
|
||||
background: -webkit-linear-gradient(45deg, #28a142, #26A65B);
|
||||
background: linear-gradient(45deg, #28a142, #26A65B)
|
||||
background-color: #26a65b;
|
||||
background: -webkit-linear-gradient(45deg, #28a142, #26a65b);
|
||||
background: linear-gradient(45deg, #28a142, #26a65b);
|
||||
}
|
||||
|
||||
.navbar {
|
||||
|
|
@ -182,7 +182,7 @@
|
|||
}
|
||||
|
||||
.navbar-header {
|
||||
text-align: center
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
|
|
@ -192,21 +192,26 @@
|
|||
display: inline-block;
|
||||
float: none;
|
||||
text-align: center;
|
||||
margin: 5px 0 0
|
||||
margin: 5px 0 0;
|
||||
}
|
||||
|
||||
.navbar-nav {
|
||||
margin-right: -15px
|
||||
margin-right: -15px;
|
||||
}
|
||||
|
||||
.navbar-nav > li > a {
|
||||
font-size: 14px
|
||||
font-size: 14px;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-brand, .navbar-default .navbar-brand:focus, .navbar-default .navbar-brand:hover, .navbar-default .navbar-nav > li > a, .navbar-default .navbar-nav > li > a:focus, .navbar-default .navbar-nav > li > a:hover {
|
||||
.navbar-default .navbar-brand,
|
||||
.navbar-default .navbar-brand:focus,
|
||||
.navbar-default .navbar-brand:hover,
|
||||
.navbar-default .navbar-nav > li > a,
|
||||
.navbar-default .navbar-nav > li > a:focus,
|
||||
.navbar-default .navbar-nav > li > a:hover {
|
||||
background: transparent;
|
||||
color: #293a46;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle {
|
||||
|
|
@ -215,88 +220,94 @@
|
|||
top: 7px;
|
||||
border-color: #fff;
|
||||
color: #293a46;
|
||||
margin-right: 0
|
||||
margin-right: 0;
|
||||
}
|
||||
|
||||
.navbar-default .navbar-toggle:hover, .navbar-default .navbar-toggle:focus {
|
||||
.navbar-default .navbar-toggle:hover,
|
||||
.navbar-default .navbar-toggle:focus {
|
||||
background: #f9f9f9;
|
||||
border-color: #f9f9f9
|
||||
border-color: #f9f9f9;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
.navbar-full .navbar-brand {
|
||||
margin-left: -25px
|
||||
margin-left: -25px;
|
||||
}
|
||||
|
||||
.navbar-tall {
|
||||
height: 125px
|
||||
height: 125px;
|
||||
}
|
||||
|
||||
.navbar-tall .navbar-header, .navbar-tall .navbar-nav {
|
||||
.navbar-tall .navbar-header,
|
||||
.navbar-tall .navbar-nav {
|
||||
line-height: 125px;
|
||||
text-align: left
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.navbar-brand {
|
||||
float: none;
|
||||
display: inline-block;
|
||||
text-align: left;
|
||||
margin: 0
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
.navbar-nav > li > a {
|
||||
display: inline-block;
|
||||
margin-left: 13px
|
||||
margin-left: 13px;
|
||||
}
|
||||
|
||||
.navbar-nav > li:first-child > a {
|
||||
margin-left: 0
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
body {
|
||||
font-size: 16px;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 300;
|
||||
line-height: 1.6
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 26px;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 18px;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 26px;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 16px;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 16px;
|
||||
font-weight: 400
|
||||
font-weight: 400;
|
||||
}
|
||||
|
||||
h1, h2, h3, h4, h5 {
|
||||
line-height: 1.4
|
||||
h1,
|
||||
h2,
|
||||
h3,
|
||||
h4,
|
||||
h5 {
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
h1, h2 {
|
||||
margin: 10px 0
|
||||
h1,
|
||||
h2 {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
h5 {
|
||||
margin: 6px 0
|
||||
margin: 6px 0;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
|
@ -304,33 +315,33 @@ h5 {
|
|||
font-size: 16px;
|
||||
font-family: Roboto, sans-serif;
|
||||
font-weight: 300;
|
||||
line-height: 1.6
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
h1 {
|
||||
font-size: 38px;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h2 {
|
||||
font-size: 26px;
|
||||
font-weight: 300;
|
||||
line-height: 1.4
|
||||
line-height: 1.4;
|
||||
}
|
||||
|
||||
h3 {
|
||||
font-size: 26px;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h4 {
|
||||
font-size: 18px;
|
||||
font-weight: 300
|
||||
font-weight: 300;
|
||||
}
|
||||
|
||||
h5 {
|
||||
font-size: 16px;
|
||||
font-weight: 400
|
||||
font-weight: 400;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -343,7 +354,8 @@ a {
|
|||
color: inherit;
|
||||
}
|
||||
|
||||
a:hover, a:focus {
|
||||
a:hover,
|
||||
a:focus {
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
|
|
@ -357,40 +369,42 @@ a:hover, a:focus {
|
|||
}
|
||||
|
||||
.text-muted {
|
||||
color: #697176
|
||||
color: #697176;
|
||||
}
|
||||
|
||||
.template-index h3 {
|
||||
font-size: 21px;
|
||||
margin-bottom: 12px
|
||||
margin-bottom: 12px;
|
||||
}
|
||||
|
||||
.template-index h4 {
|
||||
color: #697176;
|
||||
line-height: 1.6
|
||||
line-height: 1.6;
|
||||
}
|
||||
|
||||
.template-index h4 a, .template-index p a {
|
||||
color: #26A65B;
|
||||
.template-index h4 a,
|
||||
.template-index p a {
|
||||
color: #26a65b;
|
||||
}
|
||||
|
||||
.template-index h5 {
|
||||
font-size: 17px;
|
||||
margin-bottom: 8px
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.homepage-terminal-example, .homepage-code-example {
|
||||
.homepage-terminal-example,
|
||||
.homepage-code-example {
|
||||
position: relative;
|
||||
font-family: monospace;
|
||||
background: #272b38;
|
||||
color: #48d8a0;
|
||||
border-radius: 8px;
|
||||
padding: 30px
|
||||
padding: 30px;
|
||||
}
|
||||
|
||||
.homepage-terminal-example .text-muted,
|
||||
.homepage-code-example .text-muted {
|
||||
color: #6a7490
|
||||
color: #6a7490;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
|
|
@ -408,7 +422,7 @@ a:hover, a:focus {
|
|||
}
|
||||
|
||||
.hero-green {
|
||||
color: #26A65B;
|
||||
color: #26a65b;
|
||||
}
|
||||
|
||||
.hero-black {
|
||||
|
|
@ -416,7 +430,7 @@ a:hover, a:focus {
|
|||
}
|
||||
|
||||
.hero-red {
|
||||
color: #CB2C37;
|
||||
color: #cb2c37;
|
||||
}
|
||||
|
||||
.svg-icon-large {
|
||||
|
|
|
|||
|
|
@ -1 +1 @@
|
|||
import "bootstrap/dist/css/bootstrap.css";
|
||||
import 'bootstrap/dist/css/bootstrap.css';
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import handlebars, { HelperOptions } from "handlebars";
|
||||
import handlebars, { HelperOptions } from 'handlebars';
|
||||
|
||||
const loadPartial = <T>(name: string): handlebars.Template<T> => {
|
||||
let partial = handlebars.partials[name];
|
||||
if (typeof partial === "string") {
|
||||
if (typeof partial === 'string') {
|
||||
partial = handlebars.compile(partial);
|
||||
handlebars.partials[name] = partial;
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import handlebars, { HelperOptions } from "handlebars";
|
||||
import handlebars, { HelperOptions } from 'handlebars';
|
||||
|
||||
export default (name: string, options: HelperOptions): void => {
|
||||
handlebars.registerPartial(name, options.fn);
|
||||
|
|
|
|||
|
|
@ -1 +0,0 @@
|
|||
@import url("https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.13.1/styles/github.min.css");
|
||||
|
|
@ -1,9 +1,9 @@
|
|||
import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from "../../../../src/ui/js/diff2html-ui";
|
||||
import { Diff2HtmlUI, defaultDiff2HtmlUIConfig, Diff2HtmlUIConfig } from '../../../../src/ui/js/diff2html-ui-slim';
|
||||
|
||||
import "../../../main.ts";
|
||||
import "../../../main.css";
|
||||
import "./demo.css";
|
||||
import "../../../../src/ui/css/diff2html.css";
|
||||
import '../../../main.ts';
|
||||
import '../../../main.css';
|
||||
import 'highlight.js/styles/github.css';
|
||||
import '../../../../src/ui/css/diff2html.css';
|
||||
|
||||
/*
|
||||
* Example URLs:
|
||||
|
|
@ -23,18 +23,18 @@ type URLParams = {
|
|||
[key: string]: string | boolean | number | undefined;
|
||||
};
|
||||
|
||||
const searchParam = "diff";
|
||||
const searchParam = 'diff';
|
||||
|
||||
function getParamsFromSearch(search: string): URLParams {
|
||||
try {
|
||||
return search
|
||||
.split("?")[1]
|
||||
.split("&")
|
||||
.split('?')[1]
|
||||
.split('&')
|
||||
.reduce((urlParams, e) => {
|
||||
const values = e.split("=");
|
||||
const values = e.split('=');
|
||||
return {
|
||||
...urlParams,
|
||||
[values[0]]: values[1]
|
||||
[values[0]]: values[1],
|
||||
};
|
||||
}, {});
|
||||
} catch (_ignore) {
|
||||
|
|
@ -43,8 +43,8 @@ function getParamsFromSearch(search: string): URLParams {
|
|||
}
|
||||
|
||||
function validateUrl(url: string): boolean {
|
||||
return /^(?:(?:(?:https?|ftp):)?\/\/)(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)(?:\.(?:[a-z\u00a1-\uffff0-9]-*)*[a-z\u00a1-\uffff0-9]+)*(?:\.(?:[a-z\u00a1-\uffff]{2,})).?)(?::\d{2,5})?(?:[/?#]\S*)?$/i.test(
|
||||
url
|
||||
return /^(?:(?:https?|ftp):)?\/\/(?:\S+(?::\S*)?@)?(?:(?!(?:10|127)(?:\.\d{1,3}){3})(?!(?:169\.254|192\.168)(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[01])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4])|(?:[\da-z\u00a1-\uffff]-*)*[\da-z\u00a1-\uffff]+(?:\.(?:[\da-z\u00a1-\uffff]-*)*[\da-z\u00a1-\uffff]+)*\.[a-z\u00a1-\uffff]{2,}.?)(?::\d{2,5})?(?:[#/?]\S*)?$/i.test(
|
||||
url,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -55,7 +55,7 @@ type Request = {
|
|||
|
||||
function prepareRequest(url: string): Request {
|
||||
if (!validateUrl(url)) {
|
||||
const errorMsg = "Invalid url provided!";
|
||||
const errorMsg = 'Invalid url provided!';
|
||||
console.error(errorMsg);
|
||||
throw new Error(errorMsg);
|
||||
}
|
||||
|
|
@ -74,44 +74,44 @@ function prepareRequest(url: string): Request {
|
|||
|
||||
function gitLabUrlGen(userName: string, projectName: string, type: string, value: string): string {
|
||||
return (
|
||||
"https://crossorigin.me/https://gitlab.com/" + userName + "/" + projectName + "/" + type + "/" + value + ".diff"
|
||||
'https://crossorigin.me/https://gitlab.com/' + userName + '/' + projectName + '/' + type + '/' + value + '.diff'
|
||||
);
|
||||
}
|
||||
|
||||
function gitHubUrlGen(userName: string, projectName: string, type: string, value: string): string {
|
||||
headers.append("Accept", "application/vnd.github.v3.diff");
|
||||
return "https://api.github.com/repos/" + userName + "/" + projectName + "/" + type + "/" + value;
|
||||
headers.append('Accept', 'application/vnd.github.v3.diff');
|
||||
return 'https://api.github.com/repos/' + userName + '/' + projectName + '/' + type + '/' + value;
|
||||
}
|
||||
|
||||
function bitbucketUrlGen(userName: string, projectName: string, type: string, value: string): string {
|
||||
const baseUrl = "https://bitbucket.org/api/2.0/repositories/";
|
||||
if (type === "pullrequests") {
|
||||
return baseUrl + userName + "/" + projectName + "/pullrequests/" + value + "/diff";
|
||||
const baseUrl = 'https://bitbucket.org/api/2.0/repositories/';
|
||||
if (type === 'pullrequests') {
|
||||
return baseUrl + userName + '/' + projectName + '/pullrequests/' + value + '/diff';
|
||||
}
|
||||
return baseUrl + userName + "/" + projectName + "/diff/" + value;
|
||||
return baseUrl + userName + '/' + projectName + '/diff/' + value;
|
||||
}
|
||||
|
||||
let values;
|
||||
if ((values = githubCommitUrl.exec(url))) {
|
||||
fetchUrl = gitHubUrlGen(values[1], values[2], "commits", values[3]);
|
||||
fetchUrl = gitHubUrlGen(values[1], values[2], 'commits', values[3]);
|
||||
} else if ((values = githubPrUrl.exec(url))) {
|
||||
fetchUrl = gitHubUrlGen(values[1], values[2], "pulls", values[3]);
|
||||
fetchUrl = gitHubUrlGen(values[1], values[2], 'pulls', values[3]);
|
||||
} else if ((values = gitlabCommitUrl.exec(url))) {
|
||||
fetchUrl = gitLabUrlGen(values[1], values[2], "commit", values[3]);
|
||||
fetchUrl = gitLabUrlGen(values[1], values[2], 'commit', values[3]);
|
||||
} else if ((values = gitlabPrUrl.exec(url))) {
|
||||
fetchUrl = gitLabUrlGen(values[1], values[2], "merge_requests", values[3]);
|
||||
fetchUrl = gitLabUrlGen(values[1], values[2], 'merge_requests', values[3]);
|
||||
} else if ((values = bitbucketCommitUrl.exec(url))) {
|
||||
fetchUrl = bitbucketUrlGen(values[1], values[2], "commit", values[3]);
|
||||
fetchUrl = bitbucketUrlGen(values[1], values[2], 'commit', values[3]);
|
||||
} else if ((values = bitbucketPrUrl.exec(url))) {
|
||||
fetchUrl = bitbucketUrlGen(values[1], values[2], "pullrequests", values[3]);
|
||||
fetchUrl = bitbucketUrlGen(values[1], values[2], 'pullrequests', values[3]);
|
||||
} else {
|
||||
console.info("Could not parse url, using the provided url.");
|
||||
fetchUrl = "https://crossorigin.me/" + url;
|
||||
console.info('Could not parse url, using the provided url.');
|
||||
fetchUrl = 'https://crossorigin.me/' + url;
|
||||
}
|
||||
|
||||
return {
|
||||
url: fetchUrl,
|
||||
headers: headers
|
||||
headers: headers,
|
||||
};
|
||||
}
|
||||
|
||||
|
|
@ -121,13 +121,13 @@ function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
|
|||
const { diff, ...urlParamsRest } = urlParams;
|
||||
const config: URLParams = {
|
||||
...defaultDiff2HtmlUIConfig,
|
||||
...urlParamsRest
|
||||
...urlParamsRest,
|
||||
};
|
||||
|
||||
return Object.entries(config).reduce((object, [k, v]) => {
|
||||
const newObject = !Number.isNaN(Number(v))
|
||||
? { [k]: Number(v) }
|
||||
: v === "true" || v === "false"
|
||||
: v === 'true' || v === 'false'
|
||||
? { [k]: Boolean(v) }
|
||||
: { [k]: v };
|
||||
return { ...object, ...newObject };
|
||||
|
|
@ -137,14 +137,14 @@ function getConfiguration(urlParams: URLParams): Diff2HtmlUIConfig {
|
|||
async function getDiff(request: Request): Promise<string> {
|
||||
try {
|
||||
const result = await fetch(request.url, {
|
||||
method: "GET",
|
||||
method: 'GET',
|
||||
headers: request.headers,
|
||||
mode: "cors",
|
||||
cache: "default"
|
||||
mode: 'cors',
|
||||
cache: 'default',
|
||||
});
|
||||
return result.text();
|
||||
} catch (error) {
|
||||
console.error("Failed to retrieve diff", error);
|
||||
console.error('Failed to retrieve diff', error);
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
|
|
@ -152,10 +152,10 @@ async function getDiff(request: Request): Promise<string> {
|
|||
function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements): void {
|
||||
const diff2htmlUi = new Diff2HtmlUI(diffString, elements.structure.diffTarget, config);
|
||||
|
||||
if (config.outputFormat === "side-by-side") {
|
||||
elements.structure.container.style.width = "100%";
|
||||
if (config.outputFormat === 'side-by-side') {
|
||||
elements.structure.container.style.width = '100%';
|
||||
} else {
|
||||
elements.structure.container.style.width = "";
|
||||
elements.structure.container.style.width = '';
|
||||
}
|
||||
|
||||
diff2htmlUi.draw();
|
||||
|
|
@ -163,7 +163,7 @@ function draw(diffString: string, config: Diff2HtmlUIConfig, elements: Elements)
|
|||
|
||||
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";
|
||||
const currentUrl = (urlParams && urlParams[searchParam]) || 'https://github.com/rtfpessoa/diff2html/pull/106';
|
||||
|
||||
if (currentUrl !== elements.url.input.value) elements.url.input.value = currentUrl;
|
||||
|
||||
|
|
@ -178,20 +178,20 @@ async function prepareInitialState(elements: Elements): Promise<[Diff2HtmlUIConf
|
|||
function updateBrowserUrl(config: Diff2HtmlUIConfig, newDiffUrl: string): void {
|
||||
if (history.pushState) {
|
||||
const paramString = Object.entries(config)
|
||||
.map(([k, v]) => k + "=" + v)
|
||||
.join("&");
|
||||
.map(([k, v]) => k + '=' + v)
|
||||
.join('&');
|
||||
const newPageUrl =
|
||||
window.location.protocol +
|
||||
"//" +
|
||||
'//' +
|
||||
window.location.host +
|
||||
window.location.pathname +
|
||||
"?" +
|
||||
'?' +
|
||||
paramString +
|
||||
"&" +
|
||||
'&' +
|
||||
searchParam +
|
||||
"=" +
|
||||
'=' +
|
||||
newDiffUrl;
|
||||
window.history.pushState({ path: newPageUrl }, "", newPageUrl);
|
||||
window.history.pushState({ path: newPageUrl }, '', newPageUrl);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -215,15 +215,15 @@ type Elements = {
|
|||
};
|
||||
};
|
||||
|
||||
document.addEventListener("DOMContentLoaded", async () => {
|
||||
document.addEventListener('DOMContentLoaded', async () => {
|
||||
// Improves browser compatibility
|
||||
require("whatwg-fetch");
|
||||
require('whatwg-fetch');
|
||||
|
||||
const drawAndUpdateUrl = async (
|
||||
diffUrl: string,
|
||||
diffString: string,
|
||||
config: Diff2HtmlUIConfig,
|
||||
elements: Elements
|
||||
elements: Elements,
|
||||
): Promise<void> => {
|
||||
updateBrowserUrl(config, diffUrl);
|
||||
const newRequest = prepareRequest(diffUrl);
|
||||
|
|
@ -233,22 +233,22 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||
|
||||
const elements: Elements = {
|
||||
structure: {
|
||||
container: document.getElementsByClassName("container")[0] as HTMLElement,
|
||||
diffTarget: document.getElementById("url-diff-container") as HTMLElement
|
||||
container: document.getElementsByClassName('container')[0] as HTMLElement,
|
||||
diffTarget: document.getElementById('url-diff-container') as HTMLElement,
|
||||
},
|
||||
url: {
|
||||
input: document.getElementById("url") as HTMLInputElement,
|
||||
button: document.getElementById("url-btn") as HTMLElement
|
||||
input: document.getElementById('url') as HTMLInputElement,
|
||||
button: document.getElementById('url-btn') as HTMLElement,
|
||||
},
|
||||
options: {
|
||||
outputFormat: document.getElementById("diff-url-options-output-format") as HTMLInputElement,
|
||||
matching: document.getElementById("diff-url-options-matching") as HTMLInputElement,
|
||||
wordsThreshold: document.getElementById("diff-url-options-match-words-threshold") as HTMLInputElement,
|
||||
matchingMaxComparisons: document.getElementById("diff-url-options-matching-max-comparisons") as HTMLInputElement
|
||||
outputFormat: document.getElementById('diff-url-options-output-format') as HTMLInputElement,
|
||||
matching: document.getElementById('diff-url-options-matching') as HTMLInputElement,
|
||||
wordsThreshold: document.getElementById('diff-url-options-match-words-threshold') as HTMLInputElement,
|
||||
matchingMaxComparisons: document.getElementById('diff-url-options-matching-max-comparisons') as HTMLInputElement,
|
||||
},
|
||||
checkboxes: {
|
||||
drawFileList: document.getElementById("diff-url-options-show-files") as HTMLInputElement
|
||||
}
|
||||
drawFileList: document.getElementById('diff-url-options-show-files') as HTMLInputElement,
|
||||
},
|
||||
};
|
||||
|
||||
let [config, diffString] = await prepareInitialState(elements);
|
||||
|
|
@ -262,20 +262,20 @@ document.addEventListener("DOMContentLoaded", async () => {
|
|||
(elements.options.matchingMaxComparisons.value = config.matchingMaxComparisons.toString());
|
||||
|
||||
Object.entries(elements.options).forEach(([option, element]) =>
|
||||
element.addEventListener("change", () => {
|
||||
element.addEventListener('change', () => {
|
||||
config = { ...config, [option]: element.value };
|
||||
drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
Object.entries(elements.checkboxes).forEach(([option, checkbox]) =>
|
||||
checkbox.addEventListener("change", () => {
|
||||
checkbox.addEventListener('change', () => {
|
||||
config = { ...config, [option]: checkbox.checked };
|
||||
drawAndUpdateUrl(elements.url.input.value, diffString, config, elements);
|
||||
})
|
||||
}),
|
||||
);
|
||||
|
||||
elements.url.button.addEventListener("click", async e => {
|
||||
elements.url.button.addEventListener('click', async e => {
|
||||
e.preventDefault();
|
||||
const newDiffUrl = elements.url.input.value;
|
||||
const newRequest = prepareRequest(newDiffUrl);
|
||||
|
|
|
|||
|
|
@ -1,93 +1,97 @@
|
|||
.screenshot {
|
||||
display: block;
|
||||
overflow: hidden;
|
||||
}
|
||||
}
|
||||
|
||||
.screenshot > img {
|
||||
width: 100%
|
||||
}
|
||||
.screenshot > img {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.screenshots-fan {
|
||||
margin-top: 50px
|
||||
}
|
||||
.screenshots-fan {
|
||||
margin-top: 50px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot {
|
||||
.screenshots-fan .screenshot {
|
||||
position: relative;
|
||||
width: auto;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
}
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot:last-child, .screenshots-fan .screenshot:first-child {
|
||||
z-index: 2
|
||||
}
|
||||
.screenshots-fan .screenshot:last-child,
|
||||
.screenshots-fan .screenshot:first-child {
|
||||
z-index: 2;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot {
|
||||
z-index: 3
|
||||
}
|
||||
.screenshots-fan .screenshot {
|
||||
z-index: 3;
|
||||
}
|
||||
|
||||
@media (min-width: 768px) {
|
||||
@media (min-width: 768px) {
|
||||
.screenshots-fan {
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin-top: 60px;
|
||||
height: 200px
|
||||
height: 200px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot {
|
||||
height: auto;
|
||||
top: 10px;
|
||||
width: 350px
|
||||
width: 350px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot:first-child, .screenshots-fan .screenshot:last-child {
|
||||
.screenshots-fan .screenshot:first-child,
|
||||
.screenshots-fan .screenshot:last-child {
|
||||
width: 250px;
|
||||
position: absolute;
|
||||
top: 65px
|
||||
top: 65px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot:first-child {
|
||||
left: 10px
|
||||
left: 10px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot:last-child {
|
||||
left: auto;
|
||||
right: 10px
|
||||
}
|
||||
right: 10px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
@media (min-width: 992px) {
|
||||
.screenshots-fan {
|
||||
margin-top: 60px;
|
||||
height: 240px
|
||||
height: 240px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot {
|
||||
width: 400px
|
||||
width: 400px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot:first-child, .screenshots-fan .screenshot:last-child {
|
||||
width: 300px
|
||||
}
|
||||
.screenshots-fan .screenshot:first-child,
|
||||
.screenshots-fan .screenshot:last-child {
|
||||
width: 300px;
|
||||
}
|
||||
}
|
||||
|
||||
@media (min-width: 1200px) {
|
||||
@media (min-width: 1200px) {
|
||||
.screenshots-fan {
|
||||
margin-top: 80px;
|
||||
height: 380px
|
||||
height: 380px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot {
|
||||
width: 550px
|
||||
width: 550px;
|
||||
}
|
||||
|
||||
.screenshots-fan .screenshot:first-child, .screenshots-fan .screenshot:last-child {
|
||||
width: 450px
|
||||
}
|
||||
.screenshots-fan .screenshot:first-child,
|
||||
.screenshots-fan .screenshot:last-child {
|
||||
width: 450px;
|
||||
}
|
||||
}
|
||||
|
||||
.img-snapshot1 {
|
||||
background-image: url("./images/snapshot-1.png");
|
||||
background-image: url('./images/snapshot-1.png');
|
||||
background-repeat: no-repeat;
|
||||
/* height: 50px;
|
||||
width: 50px; */
|
||||
|
|
@ -95,7 +99,7 @@
|
|||
}
|
||||
|
||||
.img-snapshot2 {
|
||||
background-image: url("./images/snapshot-2.png");
|
||||
background-image: url('./images/snapshot-2.png');
|
||||
background-repeat: no-repeat;
|
||||
/* height: 50px;
|
||||
width: 50px; */
|
||||
|
|
@ -103,7 +107,7 @@
|
|||
}
|
||||
|
||||
.img-snapshot3 {
|
||||
background-image: url("./images/snapshot-3.png");
|
||||
background-image: url('./images/snapshot-3.png');
|
||||
background-repeat: no-repeat;
|
||||
/* height: 50px;
|
||||
width: 50px; */
|
||||
|
|
|
|||
|
|
@ -1,8 +1,8 @@
|
|||
import Clipboard from "clipboard";
|
||||
import Clipboard from 'clipboard';
|
||||
|
||||
import "../../../main.ts";
|
||||
import "../../../main.css";
|
||||
import "./index.css";
|
||||
import '../../../main.ts';
|
||||
import '../../../main.css';
|
||||
import './index.css';
|
||||
|
||||
// eslint-disable-next-line no-new
|
||||
new Clipboard(document.getElementsByClassName("btn-clipboard")[0]);
|
||||
new Clipboard(document.getElementsByClassName('btn-clipboard')[0]);
|
||||
|
|
|
|||
Loading…
Reference in a new issue