Chore: Add issue/pr template and general housekeeping tools and docs (#900)
* Add linting * Add issue templates and docs * Add root eslint config and remove tslint * Autofix lint issues
This commit is contained in:
21
.eslintrc.js
Normal file
21
.eslintrc.js
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
module.exports = {
|
||||||
|
env: {
|
||||||
|
browser: true,
|
||||||
|
es2021: true,
|
||||||
|
node: true,
|
||||||
|
},
|
||||||
|
extends: [
|
||||||
|
'eslint:recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended',
|
||||||
|
'plugin:@typescript-eslint/recommended-requiring-type-checking',
|
||||||
|
],
|
||||||
|
parser: '@typescript-eslint/parser',
|
||||||
|
parserOptions: {
|
||||||
|
ecmaVersion: 'latest',
|
||||||
|
sourceType: 'module',
|
||||||
|
tsconfigRootDir: __dirname,
|
||||||
|
project: ['./tsconfig.eslint.json', './packages/*/tsconfig.json'],
|
||||||
|
},
|
||||||
|
plugins: ['@typescript-eslint'],
|
||||||
|
rules: {},
|
||||||
|
};
|
||||||
45
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
45
.github/ISSUE_TEMPLATE/bug_report.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
name: Bug Report
|
||||||
|
description: Report an rrweb bug
|
||||||
|
title: '[Bug]: '
|
||||||
|
labels:
|
||||||
|
- 'bug'
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Preflight Checklist
|
||||||
|
description: Please ensure you've completed all of the following.
|
||||||
|
options:
|
||||||
|
- label: I have searched the [issue tracker](https://www.github.com/rrweb-io/rrweb/issues) for a bug report that matches the one I want to file, without success.
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: What package is this bug report for?
|
||||||
|
options:
|
||||||
|
- rrweb
|
||||||
|
- rrweb-snapshot
|
||||||
|
- rrdom
|
||||||
|
- rrweb-player
|
||||||
|
- Other (specify below)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Expected Behavior
|
||||||
|
description: A clear and concise description of what you expected to happen.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Actual Behavior
|
||||||
|
description: A clear description of what actually happens.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
attributes:
|
||||||
|
label: Testcase Gist URL
|
||||||
|
description: If you can reproduce the issue in a standalone test case, please save your recording events.json to a [GitHub gist](https://gist.github.com), paste that gist link into [rrwebdebug.com](https://rrwebdebug.com) and put the rrwebdebug.com URL here. This is **the best way** to ensure this issue is triaged quickly.
|
||||||
|
placeholder: https://rrwebdebug.com/...
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional Information
|
||||||
|
description: If your problem needs further explanation, or if the issue you're seeing cannot be reproduced in a gist, please add more information here.
|
||||||
48
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
48
.github/ISSUE_TEMPLATE/feature_request.yml
vendored
Normal file
@@ -0,0 +1,48 @@
|
|||||||
|
name: Feature Request
|
||||||
|
description: Suggest an idea for rrweb
|
||||||
|
title: '[Feature Request]: '
|
||||||
|
labels:
|
||||||
|
- 'feature request'
|
||||||
|
body:
|
||||||
|
- type: checkboxes
|
||||||
|
attributes:
|
||||||
|
label: Preflight Checklist
|
||||||
|
description: Please ensure you've completed all of the following.
|
||||||
|
options:
|
||||||
|
- label: I have searched the [issue tracker](https://www.github.com/rrweb-io/rrweb/issues) for a feature request that matches the one I want to file, without success.
|
||||||
|
required: true
|
||||||
|
- type: dropdown
|
||||||
|
attributes:
|
||||||
|
label: What package is this feature request for?
|
||||||
|
options:
|
||||||
|
- rrweb
|
||||||
|
- rrweb-snapshot
|
||||||
|
- rrdom
|
||||||
|
- rrweb-player
|
||||||
|
- Other (specify below)
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Problem Description
|
||||||
|
description: Please add a clear and concise description of the problem you are seeking to solve with this feature request.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Proposed Solution
|
||||||
|
description: Describe the solution you'd like in a clear and concise manner.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Alternatives Considered
|
||||||
|
description: A clear and concise description of any alternative solutions or features you've considered.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
attributes:
|
||||||
|
label: Additional Information
|
||||||
|
description: Add any other context about the problem here.
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
19
.github/config.yml
vendored
Normal file
19
.github/config.yml
vendored
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
# Comment to be posted to on PRs from first time contributors in your repository
|
||||||
|
newPRWelcomeComment: |
|
||||||
|
💖 Thanks for opening this pull request! 💖
|
||||||
|
|
||||||
|
Things that will help get your PR across the finish line:
|
||||||
|
|
||||||
|
- Follow the TypeScript [coding style](https://github.com/rrweb-io/rrweb/blob/master/docs/development/coding-style.md).
|
||||||
|
- Run `yarn lint` locally to catch formatting errors earlier.
|
||||||
|
- Document any user-facing changes you've made following the [documentation styleguide](https://github.com/rrweb-io/rrweb/blob/master/blob/main/docs/styleguide.md).
|
||||||
|
- Include tests when adding/changing behavior.
|
||||||
|
- Include screenshots and animated GIFs whenever possible.
|
||||||
|
|
||||||
|
We get a lot of pull requests on this repo, so please be patient and we will get back to you as soon as we can.
|
||||||
|
|
||||||
|
# Configuration for first-pr-merge - https://github.com/behaviorbot/first-pr-merge
|
||||||
|
|
||||||
|
# Comment to be posted to on pull requests merged by a first time user
|
||||||
|
firstPRMergeComment: >
|
||||||
|
Congrats on merging your first pull request! 🎉🎉🎉Hallo
|
||||||
239
.markdownlint.yml
Normal file
239
.markdownlint.yml
Normal file
@@ -0,0 +1,239 @@
|
|||||||
|
# markdownlint YAML configuration with all properties set to their default value
|
||||||
|
|
||||||
|
# Default state for all rules
|
||||||
|
default: true
|
||||||
|
|
||||||
|
# Path to configuration file to extend
|
||||||
|
extends: null
|
||||||
|
|
||||||
|
# MD001/heading-increment/header-increment - Heading levels should only increment by one level at a time
|
||||||
|
MD001: true
|
||||||
|
|
||||||
|
# MD002/first-heading-h1/first-header-h1 - First heading should be a top-level heading
|
||||||
|
MD002:
|
||||||
|
# Heading level
|
||||||
|
level: 1
|
||||||
|
|
||||||
|
# MD003/heading-style/header-style - Heading style
|
||||||
|
MD003:
|
||||||
|
# Heading style
|
||||||
|
style: 'consistent'
|
||||||
|
|
||||||
|
# MD004/ul-style - Unordered list style
|
||||||
|
MD004:
|
||||||
|
# List style
|
||||||
|
style: 'consistent'
|
||||||
|
|
||||||
|
# MD005/list-indent - Inconsistent indentation for list items at the same level
|
||||||
|
MD005: true
|
||||||
|
|
||||||
|
# MD006/ul-start-left - Consider starting bulleted lists at the beginning of the line
|
||||||
|
MD006: true
|
||||||
|
|
||||||
|
# MD007/ul-indent - Unordered list indentation
|
||||||
|
MD007:
|
||||||
|
# Spaces for indent
|
||||||
|
indent: 2
|
||||||
|
# Whether to indent the first level of the list
|
||||||
|
start_indented: false
|
||||||
|
# Spaces for first level indent (when start_indented is set)
|
||||||
|
start_indent: 2
|
||||||
|
|
||||||
|
# MD009/no-trailing-spaces - Trailing spaces
|
||||||
|
MD009:
|
||||||
|
# Spaces for line break
|
||||||
|
br_spaces: 2
|
||||||
|
# Allow spaces for empty lines in list items
|
||||||
|
list_item_empty_lines: false
|
||||||
|
# Include unnecessary breaks
|
||||||
|
strict: false
|
||||||
|
|
||||||
|
# MD010/no-hard-tabs - Hard tabs
|
||||||
|
MD010:
|
||||||
|
# Include code blocks
|
||||||
|
code_blocks: true
|
||||||
|
# Number of spaces for each hard tab
|
||||||
|
spaces_per_tab: 1
|
||||||
|
|
||||||
|
# MD011/no-reversed-links - Reversed link syntax
|
||||||
|
MD011: true
|
||||||
|
|
||||||
|
# MD012/no-multiple-blanks - Multiple consecutive blank lines
|
||||||
|
MD012:
|
||||||
|
# Consecutive blank lines
|
||||||
|
maximum: 1
|
||||||
|
|
||||||
|
# MD013/line-length - Line length
|
||||||
|
MD013:
|
||||||
|
# Number of characters
|
||||||
|
line_length: 80
|
||||||
|
# Number of characters for headings
|
||||||
|
heading_line_length: 80
|
||||||
|
# Number of characters for code blocks
|
||||||
|
code_block_line_length: 80
|
||||||
|
# Include code blocks
|
||||||
|
code_blocks: true
|
||||||
|
# Include tables
|
||||||
|
tables: true
|
||||||
|
# Include headings
|
||||||
|
headings: true
|
||||||
|
# Include headings
|
||||||
|
headers: true
|
||||||
|
# Strict length checking
|
||||||
|
strict: false
|
||||||
|
# Stern length checking
|
||||||
|
stern: false
|
||||||
|
|
||||||
|
# MD014/commands-show-output - Dollar signs used before commands without showing output
|
||||||
|
MD014: true
|
||||||
|
|
||||||
|
# MD018/no-missing-space-atx - No space after hash on atx style heading
|
||||||
|
MD018: true
|
||||||
|
|
||||||
|
# MD019/no-multiple-space-atx - Multiple spaces after hash on atx style heading
|
||||||
|
MD019: true
|
||||||
|
|
||||||
|
# MD020/no-missing-space-closed-atx - No space inside hashes on closed atx style heading
|
||||||
|
MD020: true
|
||||||
|
|
||||||
|
# MD021/no-multiple-space-closed-atx - Multiple spaces inside hashes on closed atx style heading
|
||||||
|
MD021: true
|
||||||
|
|
||||||
|
# MD022/blanks-around-headings/blanks-around-headers - Headings should be surrounded by blank lines
|
||||||
|
MD022:
|
||||||
|
# Blank lines above heading
|
||||||
|
lines_above: 1
|
||||||
|
# Blank lines below heading
|
||||||
|
lines_below: 1
|
||||||
|
|
||||||
|
# MD023/heading-start-left/header-start-left - Headings must start at the beginning of the line
|
||||||
|
MD023: true
|
||||||
|
|
||||||
|
# MD024/no-duplicate-heading/no-duplicate-header - Multiple headings with the same content
|
||||||
|
MD024:
|
||||||
|
# Only check sibling headings
|
||||||
|
allow_different_nesting: false
|
||||||
|
# Only check sibling headings
|
||||||
|
siblings_only: false
|
||||||
|
|
||||||
|
# MD025/single-title/single-h1 - Multiple top-level headings in the same document
|
||||||
|
MD025:
|
||||||
|
# Heading level
|
||||||
|
level: 1
|
||||||
|
# RegExp for matching title in front matter
|
||||||
|
front_matter_title: "^\\s*title\\s*[:=]"
|
||||||
|
|
||||||
|
# MD026/no-trailing-punctuation - Trailing punctuation in heading
|
||||||
|
MD026:
|
||||||
|
# Punctuation characters
|
||||||
|
punctuation: '.,;:!。,;:!'
|
||||||
|
|
||||||
|
# MD027/no-multiple-space-blockquote - Multiple spaces after blockquote symbol
|
||||||
|
MD027: true
|
||||||
|
|
||||||
|
# MD028/no-blanks-blockquote - Blank line inside blockquote
|
||||||
|
MD028: true
|
||||||
|
|
||||||
|
# MD029/ol-prefix - Ordered list item prefix
|
||||||
|
MD029:
|
||||||
|
# List style
|
||||||
|
style: 'one_or_ordered'
|
||||||
|
|
||||||
|
# MD030/list-marker-space - Spaces after list markers
|
||||||
|
MD030:
|
||||||
|
# Spaces for single-line unordered list items
|
||||||
|
ul_single: 1
|
||||||
|
# Spaces for single-line ordered list items
|
||||||
|
ol_single: 1
|
||||||
|
# Spaces for multi-line unordered list items
|
||||||
|
ul_multi: 1
|
||||||
|
# Spaces for multi-line ordered list items
|
||||||
|
ol_multi: 1
|
||||||
|
|
||||||
|
# MD031/blanks-around-fences - Fenced code blocks should be surrounded by blank lines
|
||||||
|
MD031:
|
||||||
|
# Include list items
|
||||||
|
list_items: true
|
||||||
|
|
||||||
|
# MD032/blanks-around-lists - Lists should be surrounded by blank lines
|
||||||
|
MD032: true
|
||||||
|
|
||||||
|
# MD033/no-inline-html - Inline HTML
|
||||||
|
MD033:
|
||||||
|
# Allowed elements
|
||||||
|
allowed_elements: []
|
||||||
|
|
||||||
|
# MD034/no-bare-urls - Bare URL used
|
||||||
|
MD034: true
|
||||||
|
|
||||||
|
# MD035/hr-style - Horizontal rule style
|
||||||
|
MD035:
|
||||||
|
# Horizontal rule style
|
||||||
|
style: 'consistent'
|
||||||
|
|
||||||
|
# MD036/no-emphasis-as-heading/no-emphasis-as-header - Emphasis used instead of a heading
|
||||||
|
MD036:
|
||||||
|
# Punctuation characters
|
||||||
|
punctuation: '.,;:!?。,;:!?'
|
||||||
|
|
||||||
|
# MD037/no-space-in-emphasis - Spaces inside emphasis markers
|
||||||
|
MD037: true
|
||||||
|
|
||||||
|
# MD038/no-space-in-code - Spaces inside code span elements
|
||||||
|
MD038: true
|
||||||
|
|
||||||
|
# MD039/no-space-in-links - Spaces inside link text
|
||||||
|
MD039: true
|
||||||
|
|
||||||
|
# MD040/fenced-code-language - Fenced code blocks should have a language specified
|
||||||
|
MD040: true
|
||||||
|
|
||||||
|
# MD041/first-line-heading/first-line-h1 - First line in a file should be a top-level heading
|
||||||
|
MD041:
|
||||||
|
# Heading level
|
||||||
|
level: 1
|
||||||
|
# RegExp for matching title in front matter
|
||||||
|
front_matter_title: "^\\s*title\\s*[:=]"
|
||||||
|
|
||||||
|
# MD042/no-empty-links - No empty links
|
||||||
|
MD042: true
|
||||||
|
|
||||||
|
# MD043/required-headings/required-headers - Required heading structure
|
||||||
|
MD043:
|
||||||
|
# List of headings
|
||||||
|
headings: []
|
||||||
|
# List of headings
|
||||||
|
headers: []
|
||||||
|
|
||||||
|
# MD044/proper-names - Proper names should have the correct capitalization
|
||||||
|
MD044:
|
||||||
|
# List of proper names
|
||||||
|
names: []
|
||||||
|
# Include code blocks
|
||||||
|
code_blocks: true
|
||||||
|
|
||||||
|
# MD045/no-alt-text - Images should have alternate text (alt text)
|
||||||
|
MD045: true
|
||||||
|
|
||||||
|
# MD046/code-block-style - Code block style
|
||||||
|
MD046:
|
||||||
|
# Block style
|
||||||
|
style: 'consistent'
|
||||||
|
|
||||||
|
# MD047/single-trailing-newline - Files should end with a single newline character
|
||||||
|
MD047: true
|
||||||
|
|
||||||
|
# MD048/code-fence-style - Code fence style
|
||||||
|
MD048:
|
||||||
|
# Code fence style
|
||||||
|
style: 'consistent'
|
||||||
|
|
||||||
|
# MD049/emphasis-style - Emphasis style should be consistent
|
||||||
|
MD049:
|
||||||
|
# Emphasis style should be consistent
|
||||||
|
style: 'consistent'
|
||||||
|
|
||||||
|
# MD050/strong-style - Strong style should be consistent
|
||||||
|
MD050:
|
||||||
|
# Strong style should be consistent
|
||||||
|
style: 'consistent'
|
||||||
52
docs/development/coding-style.md
Normal file
52
docs/development/coding-style.md
Normal file
@@ -0,0 +1,52 @@
|
|||||||
|
# Coding Style
|
||||||
|
|
||||||
|
These are the style guidelines for coding in Electron.
|
||||||
|
|
||||||
|
You can run `yarn lint` to show any style issues detected by `tslint` and
|
||||||
|
`eslint`.
|
||||||
|
|
||||||
|
## General Code
|
||||||
|
|
||||||
|
- End files with a newline.
|
||||||
|
- Using a plain `return` when returning explicitly at the end of a function.
|
||||||
|
- Not `return null`, `return undefined`, `null` or `undefined`
|
||||||
|
|
||||||
|
## Documentation
|
||||||
|
|
||||||
|
- Write [remark](https://github.com/remarkjs/remark) markdown style.
|
||||||
|
|
||||||
|
<!-- You can run `yarn lint-docs` to ensure that your documentation changes are
|
||||||
|
formatted correctly. -->
|
||||||
|
|
||||||
|
## TypeScript
|
||||||
|
|
||||||
|
- Write [standard](https://www.npmjs.com/package/standard) JavaScript style.
|
||||||
|
- File names should be concatenated with `-` instead of `_`, e.g.
|
||||||
|
`file-name.js` rather than `file_name.js`, because in
|
||||||
|
[github/atom](https://github.com/github/atom) module names are usually in
|
||||||
|
the `module-name` form. This rule only applies to `.js` files.
|
||||||
|
- Use newer ES6/ES2015 syntax where appropriate
|
||||||
|
- [`const`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/const)
|
||||||
|
for requires and other constants. If the value is a primitive, use uppercase naming (eg `const NUMBER_OF_RETRIES = 5`).
|
||||||
|
- [`let`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/let)
|
||||||
|
for defining variables
|
||||||
|
- [Arrow functions](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions)
|
||||||
|
instead of `function () { }`
|
||||||
|
- [Template literals](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Template_literals)
|
||||||
|
instead of string concatenation using `+`
|
||||||
|
|
||||||
|
## Naming Things
|
||||||
|
|
||||||
|
Electron APIs uses the same capitalization scheme as Node.js:
|
||||||
|
|
||||||
|
- When the module itself is a class like `BrowserWindow`, use `PascalCase`.
|
||||||
|
- When the module is a set of APIs, like `globalShortcut`, use `camelCase`.
|
||||||
|
- When the API is a property of object, and it is complex enough to be in a
|
||||||
|
separate chapter like `win.webContents`, use `mixedCase`.
|
||||||
|
- For other non-module APIs, use natural titles, like `<webview> Tag` or
|
||||||
|
`Process Object`.
|
||||||
|
|
||||||
|
When creating a new API, it is preferred to use getters and setters instead of
|
||||||
|
jQuery's one-function style. For example, `.getText()` and `.setText(text)`
|
||||||
|
are preferred to `.text([text])`. There is a
|
||||||
|
[discussion](https://github.com/electron/electron/issues/46) on this.
|
||||||
72
docs/styleguilde.md
Normal file
72
docs/styleguilde.md
Normal file
@@ -0,0 +1,72 @@
|
|||||||
|
# rrweb Documentation Style Guide
|
||||||
|
|
||||||
|
These are the guidelines for writing rrweb documentation.
|
||||||
|
|
||||||
|
## Headings
|
||||||
|
|
||||||
|
- Each page must have a single `#`-level title at the top.
|
||||||
|
- Chapters in the same page must have `##`-level headings.
|
||||||
|
- Sub-chapters need to increase the number of `#` in the heading according to
|
||||||
|
their nesting depth.
|
||||||
|
- The page's title must follow [APA title case][title-case].
|
||||||
|
- All chapters must follow [APA sentence case][sentence-case].
|
||||||
|
|
||||||
|
Using `Quick Start` as example:
|
||||||
|
|
||||||
|
```markdown
|
||||||
|
# Quick Start
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
## Replay
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
## Record
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
## Events
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
### Understanding Events
|
||||||
|
|
||||||
|
...
|
||||||
|
|
||||||
|
### Custom Events
|
||||||
|
|
||||||
|
...
|
||||||
|
```
|
||||||
|
|
||||||
|
For API references, there are exceptions to this rule.
|
||||||
|
|
||||||
|
## Markdown rules
|
||||||
|
|
||||||
|
This repository uses the [`markdownlint`][markdownlint] package to enforce consistent
|
||||||
|
Markdown styling. For the exact rules, see the `.markdownlint.yaml` file in the root
|
||||||
|
folder.
|
||||||
|
|
||||||
|
There are a few style guidelines that aren't covered by the linter rules:
|
||||||
|
|
||||||
|
<!--TODO(erickzhao): make sure this matches with the lint:markdownlint task-->
|
||||||
|
|
||||||
|
- Use `sh` instead of `cmd` in code blocks (due to the syntax highlighter).
|
||||||
|
- Keep line lengths between 80 and 100 characters if possible for readability
|
||||||
|
purposes.
|
||||||
|
- No nesting lists more than 2 levels (due to the markdown renderer).
|
||||||
|
- All `js` and `javascript` code blocks are linted with
|
||||||
|
[standard-markdown](https://www.npmjs.com/package/standard-markdown).
|
||||||
|
- For unordered lists, use asterisks instead of dashes.
|
||||||
|
|
||||||
|
## Picking words
|
||||||
|
|
||||||
|
- Use "will" over "would" when describing outcomes.
|
||||||
|
|
||||||
|
## Documentation translations
|
||||||
|
|
||||||
|
When adding something to an English doc file, please add a translation if possible, or a placeholder in the respective \*.zh-CN.md files.
|
||||||
|
|
||||||
|
[title-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/title-case
|
||||||
|
[sentence-case]: https://apastyle.apa.org/style-grammar-guidelines/capitalization/sentence-case
|
||||||
|
[markdownlint]: https://github.com/DavidAnson/markdownlint
|
||||||
12
package.json
12
package.json
@@ -21,7 +21,14 @@
|
|||||||
"packages/rrdom"
|
"packages/rrdom"
|
||||||
],
|
],
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"lerna": "^4.0.0"
|
"@typescript-eslint/eslint-plugin": "^5.25.0",
|
||||||
|
"@typescript-eslint/parser": "^5.25.0",
|
||||||
|
"concurrently": "^7.1.0",
|
||||||
|
"eslint": "^8.15.0",
|
||||||
|
"lerna": "^4.0.0",
|
||||||
|
"markdownlint": "^0.25.1",
|
||||||
|
"markdownlint-cli": "^0.31.1",
|
||||||
|
"typescript": "^4.6.4"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lerna": "lerna",
|
"lerna": "lerna",
|
||||||
@@ -29,7 +36,8 @@
|
|||||||
"test": "yarn lerna run test",
|
"test": "yarn lerna run test",
|
||||||
"test:watch": "yarn lerna run test:watch --parallel",
|
"test:watch": "yarn lerna run test:watch --parallel",
|
||||||
"dev": "yarn lerna run dev --parallel",
|
"dev": "yarn lerna run dev --parallel",
|
||||||
"repl": "cd packages/rrweb && npm run repl"
|
"repl": "cd packages/rrweb && npm run repl",
|
||||||
|
"lint": "yarn run concurrently --success=all -r -m=1 'yarn run markdownlint docs' 'yarn eslint packages/*/src --ext .ts,.tsx,.js,.jsx,.svelte'"
|
||||||
},
|
},
|
||||||
"resolutions": {
|
"resolutions": {
|
||||||
"**/jsdom/cssom": "^0.5.0"
|
"**/jsdom/cssom": "^0.5.0"
|
||||||
|
|||||||
@@ -7,7 +7,8 @@
|
|||||||
"bundle:es-only": "cross-env ES_ONLY=true rollup --config",
|
"bundle:es-only": "cross-env ES_ONLY=true rollup --config",
|
||||||
"check-types": "tsc -noEmit",
|
"check-types": "tsc -noEmit",
|
||||||
"test": "jest",
|
"test": "jest",
|
||||||
"prepublish": "npm run bundle"
|
"prepublish": "npm run bundle",
|
||||||
|
"lint": "yarn eslint src/**/*.ts"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"rrweb",
|
"rrweb",
|
||||||
@@ -32,7 +33,10 @@
|
|||||||
"@types/jest": "^27.4.1",
|
"@types/jest": "^27.4.1",
|
||||||
"@types/nwsapi": "^2.2.2",
|
"@types/nwsapi": "^2.2.2",
|
||||||
"@types/puppeteer": "^5.4.4",
|
"@types/puppeteer": "^5.4.4",
|
||||||
|
"@typescript-eslint/eslint-plugin": "^5.23.0",
|
||||||
|
"@typescript-eslint/parser": "^5.23.0",
|
||||||
"compare-versions": "^4.1.3",
|
"compare-versions": "^4.1.3",
|
||||||
|
"eslint": "^8.15.0",
|
||||||
"jest": "^27.5.1",
|
"jest": "^27.5.1",
|
||||||
"puppeteer": "^9.1.1",
|
"puppeteer": "^9.1.1",
|
||||||
"rollup": "^2.56.3",
|
"rollup": "^2.56.3",
|
||||||
|
|||||||
@@ -107,20 +107,21 @@ export function diff(
|
|||||||
let inputDataToApply = null,
|
let inputDataToApply = null,
|
||||||
scrollDataToApply = null;
|
scrollDataToApply = null;
|
||||||
switch (newTree.RRNodeType) {
|
switch (newTree.RRNodeType) {
|
||||||
case RRNodeType.Document:
|
case RRNodeType.Document: {
|
||||||
const newRRDocument = newTree as IRRDocument;
|
const newRRDocument = newTree as IRRDocument;
|
||||||
scrollDataToApply = (newRRDocument as RRDocument).scrollData;
|
scrollDataToApply = (newRRDocument as RRDocument).scrollData;
|
||||||
break;
|
break;
|
||||||
case RRNodeType.Element:
|
}
|
||||||
const oldElement = (oldTree as Node) as HTMLElement;
|
case RRNodeType.Element: {
|
||||||
|
const oldElement = (oldTree ) as HTMLElement;
|
||||||
const newRRElement = newTree as IRRElement;
|
const newRRElement = newTree as IRRElement;
|
||||||
diffProps(oldElement, newRRElement, rrnodeMirror);
|
diffProps(oldElement, newRRElement, rrnodeMirror);
|
||||||
scrollDataToApply = (newRRElement as RRElement).scrollData;
|
scrollDataToApply = (newRRElement as RRElement).scrollData;
|
||||||
inputDataToApply = (newRRElement as RRElement).inputData;
|
inputDataToApply = (newRRElement as RRElement).inputData;
|
||||||
switch (newRRElement.tagName) {
|
switch (newRRElement.tagName) {
|
||||||
case 'AUDIO':
|
case 'AUDIO':
|
||||||
case 'VIDEO':
|
case 'VIDEO': {
|
||||||
const oldMediaElement = (oldTree as Node) as HTMLMediaElement;
|
const oldMediaElement = (oldTree ) as HTMLMediaElement;
|
||||||
const newMediaRRElement = newRRElement as RRMediaElement;
|
const newMediaRRElement = newRRElement as RRMediaElement;
|
||||||
if (newMediaRRElement.paused !== undefined)
|
if (newMediaRRElement.paused !== undefined)
|
||||||
newMediaRRElement.paused
|
newMediaRRElement.paused
|
||||||
@@ -133,13 +134,14 @@ export function diff(
|
|||||||
if (newMediaRRElement.currentTime !== undefined)
|
if (newMediaRRElement.currentTime !== undefined)
|
||||||
oldMediaElement.currentTime = newMediaRRElement.currentTime;
|
oldMediaElement.currentTime = newMediaRRElement.currentTime;
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case 'CANVAS':
|
case 'CANVAS':
|
||||||
(newTree as RRCanvasElement).canvasMutations.forEach(
|
(newTree as RRCanvasElement).canvasMutations.forEach(
|
||||||
(canvasMutation) =>
|
(canvasMutation) =>
|
||||||
replayer.applyCanvas(
|
replayer.applyCanvas(
|
||||||
canvasMutation.event,
|
canvasMutation.event,
|
||||||
canvasMutation.mutation,
|
canvasMutation.mutation,
|
||||||
(oldTree as Node) as HTMLCanvasElement,
|
(oldTree ) as HTMLCanvasElement,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
@@ -164,6 +166,7 @@ export function diff(
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RRNodeType.Text:
|
case RRNodeType.Text:
|
||||||
case RRNodeType.Comment:
|
case RRNodeType.Comment:
|
||||||
case RRNodeType.CDATA:
|
case RRNodeType.CDATA:
|
||||||
@@ -188,7 +191,7 @@ export function diff(
|
|||||||
|
|
||||||
// IFrame element doesn't have child nodes.
|
// IFrame element doesn't have child nodes.
|
||||||
if (newTree.nodeName === 'IFRAME') {
|
if (newTree.nodeName === 'IFRAME') {
|
||||||
const oldContentDocument = ((oldTree as Node) as HTMLIFrameElement)
|
const oldContentDocument = ((oldTree ) as HTMLIFrameElement)
|
||||||
.contentDocument;
|
.contentDocument;
|
||||||
const newIFrameElement = newTree as RRIFrameElement;
|
const newIFrameElement = newTree as RRIFrameElement;
|
||||||
// If the iframe is cross-origin, the contentDocument will be null.
|
// If the iframe is cross-origin, the contentDocument will be null.
|
||||||
@@ -316,10 +319,10 @@ function diffChildren(
|
|||||||
if (
|
if (
|
||||||
replayer.mirror.getMeta(parentNode)?.type === RRNodeType.Document &&
|
replayer.mirror.getMeta(parentNode)?.type === RRNodeType.Document &&
|
||||||
replayer.mirror.getMeta(newNode)?.type === RRNodeType.Element &&
|
replayer.mirror.getMeta(newNode)?.type === RRNodeType.Element &&
|
||||||
((parentNode as Node) as Document).documentElement
|
((parentNode ) as Document).documentElement
|
||||||
) {
|
) {
|
||||||
parentNode.removeChild(
|
parentNode.removeChild(
|
||||||
((parentNode as Node) as Document).documentElement,
|
((parentNode ) as Document).documentElement,
|
||||||
);
|
);
|
||||||
oldChildren[oldStartIndex] = undefined;
|
oldChildren[oldStartIndex] = undefined;
|
||||||
oldStartNode = undefined;
|
oldStartNode = undefined;
|
||||||
@@ -379,7 +382,7 @@ export function createOrGetNode(
|
|||||||
(rrNode as IRRDocumentType).systemId,
|
(rrNode as IRRDocumentType).systemId,
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case RRNodeType.Element:
|
case RRNodeType.Element: {
|
||||||
let tagName = (rrNode as IRRElement).tagName.toLowerCase();
|
let tagName = (rrNode as IRRElement).tagName.toLowerCase();
|
||||||
tagName = SVGTagMap[tagName] || tagName;
|
tagName = SVGTagMap[tagName] || tagName;
|
||||||
if (sn && 'isSVG' in sn && sn?.isSVG) {
|
if (sn && 'isSVG' in sn && sn?.isSVG) {
|
||||||
@@ -389,6 +392,7 @@ export function createOrGetNode(
|
|||||||
);
|
);
|
||||||
} else node = document.createElement((rrNode as IRRElement).tagName);
|
} else node = document.createElement((rrNode as IRRElement).tagName);
|
||||||
break;
|
break;
|
||||||
|
}
|
||||||
case RRNodeType.Text:
|
case RRNodeType.Text:
|
||||||
node = document.createTextNode((rrNode as IRRText).data);
|
node = document.createTextNode((rrNode as IRRText).data);
|
||||||
break;
|
break;
|
||||||
@@ -413,7 +417,7 @@ export function getNestedRule(
|
|||||||
return rule;
|
return rule;
|
||||||
} else {
|
} else {
|
||||||
return getNestedRule(
|
return getNestedRule(
|
||||||
((rule as CSSGroupingRule).cssRules[position[1]] as CSSGroupingRule)
|
((rule ).cssRules[position[1]] as CSSGroupingRule)
|
||||||
.cssRules,
|
.cssRules,
|
||||||
position.slice(2),
|
position.slice(2),
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -70,7 +70,7 @@ export class RRDocument
|
|||||||
}
|
}
|
||||||
|
|
||||||
get firstElementChild(): RRElement | null {
|
get firstElementChild(): RRElement | null {
|
||||||
return this.documentElement as RRElement | null;
|
return this.documentElement;
|
||||||
}
|
}
|
||||||
|
|
||||||
appendChild(childNode: RRNode) {
|
appendChild(childNode: RRNode) {
|
||||||
@@ -87,21 +87,19 @@ export class RRDocument
|
|||||||
|
|
||||||
getElementsByTagName(tagName: string): RRElement[] {
|
getElementsByTagName(tagName: string): RRElement[] {
|
||||||
if (this.documentElement)
|
if (this.documentElement)
|
||||||
return (this.documentElement as RRElement).getElementsByTagName(tagName);
|
return this.documentElement.getElementsByTagName(tagName);
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getElementsByClassName(className: string): RRElement[] {
|
getElementsByClassName(className: string): RRElement[] {
|
||||||
if (this.documentElement)
|
if (this.documentElement)
|
||||||
return (this.documentElement as RRElement).getElementsByClassName(
|
return this.documentElement.getElementsByClassName(className);
|
||||||
className,
|
|
||||||
);
|
|
||||||
return [];
|
return [];
|
||||||
}
|
}
|
||||||
|
|
||||||
getElementById(elementId: string): RRElement | null {
|
getElementById(elementId: string): RRElement | null {
|
||||||
if (this.documentElement)
|
if (this.documentElement)
|
||||||
return (this.documentElement as RRElement).getElementById(elementId);
|
return this.documentElement.getElementById(elementId);
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -217,7 +215,7 @@ export class RRElement extends BaseRRElementImpl(RRNode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
getAttribute(name: string) {
|
getAttribute(name: string) {
|
||||||
let upperName = name && name.toLowerCase();
|
const upperName = name && name.toLowerCase();
|
||||||
if (upperName in this.attributes) return this.attributes[upperName];
|
if (upperName in this.attributes) return this.attributes[upperName];
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
@@ -231,16 +229,16 @@ export class RRElement extends BaseRRElementImpl(RRNode) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
get firstElementChild(): RRElement | null {
|
get firstElementChild(): RRElement | null {
|
||||||
for (let child of this.childNodes)
|
for (const child of this.childNodes)
|
||||||
if (child.RRNodeType === RRNodeType.Element) return child as RRElement;
|
if (child.RRNodeType === RRNodeType.Element) return child as RRElement;
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
get nextElementSibling(): RRElement | null {
|
get nextElementSibling(): RRElement | null {
|
||||||
let parentNode = this.parentNode;
|
const parentNode = this.parentNode;
|
||||||
if (!parentNode) return null;
|
if (!parentNode) return null;
|
||||||
const siblings = parentNode.childNodes;
|
const siblings = parentNode.childNodes;
|
||||||
let index = siblings.indexOf(this);
|
const index = siblings.indexOf(this);
|
||||||
for (let i = index + 1; i < siblings.length; i++)
|
for (let i = index + 1; i < siblings.length; i++)
|
||||||
if (siblings[i] instanceof RRElement) return siblings[i] as RRElement;
|
if (siblings[i] instanceof RRElement) return siblings[i] as RRElement;
|
||||||
return null;
|
return null;
|
||||||
@@ -327,7 +325,7 @@ export class RRStyleElement extends RRElement {
|
|||||||
get sheet() {
|
get sheet() {
|
||||||
if (!this._sheet) {
|
if (!this._sheet) {
|
||||||
let result = '';
|
let result = '';
|
||||||
for (let child of this.childNodes)
|
for (const child of this.childNodes)
|
||||||
if (child.RRNodeType === RRNodeType.Text)
|
if (child.RRNodeType === RRNodeType.Text)
|
||||||
result += (child as RRText).textContent;
|
result += (child as RRText).textContent;
|
||||||
this._sheet = cssom.parse(result);
|
this._sheet = cssom.parse(result);
|
||||||
@@ -337,9 +335,9 @@ export class RRStyleElement extends RRElement {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export class RRIFrameElement extends RRElement {
|
export class RRIFrameElement extends RRElement {
|
||||||
width: string = '';
|
width = '';
|
||||||
height: string = '';
|
height = '';
|
||||||
src: string = '';
|
src = '';
|
||||||
contentDocument: RRDocument = new RRDocument();
|
contentDocument: RRDocument = new RRDocument();
|
||||||
contentWindow: RRWindow = new RRWindow();
|
contentWindow: RRWindow = new RRWindow();
|
||||||
|
|
||||||
|
|||||||
@@ -118,7 +118,9 @@ export interface IRRCDATASection extends IRRNode {
|
|||||||
data: string;
|
data: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
type ConstrainedConstructor<T = {}> = new (...args: any[]) => T;
|
type ConstrainedConstructor<T = Record<string, unknown>> = new (
|
||||||
|
...args: any[]
|
||||||
|
) => T;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This is designed as an abstract class so it should never be instantiated.
|
* This is designed as an abstract class so it should never be instantiated.
|
||||||
@@ -136,7 +138,9 @@ export class BaseRRNode implements IRRNode {
|
|||||||
public readonly nodeName: string;
|
public readonly nodeName: string;
|
||||||
public readonly RRNodeType: RRNodeType;
|
public readonly RRNodeType: RRNodeType;
|
||||||
|
|
||||||
constructor(...args: any[]) {}
|
constructor(...args: any[]) {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
public get firstChild(): IRRNode | null {
|
public get firstChild(): IRRNode | null {
|
||||||
return this.childNodes[0] || null;
|
return this.childNodes[0] || null;
|
||||||
@@ -147,10 +151,10 @@ export class BaseRRNode implements IRRNode {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public get nextSibling(): IRRNode | null {
|
public get nextSibling(): IRRNode | null {
|
||||||
let parentNode = this.parentNode;
|
const parentNode = this.parentNode;
|
||||||
if (!parentNode) return null;
|
if (!parentNode) return null;
|
||||||
const siblings = parentNode.childNodes;
|
const siblings = parentNode.childNodes;
|
||||||
let index = siblings.indexOf(this);
|
const index = siblings.indexOf(this);
|
||||||
return siblings[index + 1] || null;
|
return siblings[index + 1] || null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -295,7 +299,9 @@ export function BaseRRDocumentImpl<
|
|||||||
this.childNodes = [];
|
this.childNodes = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
public close() {}
|
public close() {
|
||||||
|
//
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Adhoc implementation for setting xhtml namespace in rebuilt.ts (rrweb-snapshot).
|
* Adhoc implementation for setting xhtml namespace in rebuilt.ts (rrweb-snapshot).
|
||||||
@@ -381,6 +387,7 @@ export function BaseRRDocumentImpl<
|
|||||||
export function BaseRRDocumentTypeImpl<
|
export function BaseRRDocumentTypeImpl<
|
||||||
RRNode extends ConstrainedConstructor<IRRNode>
|
RRNode extends ConstrainedConstructor<IRRNode>
|
||||||
>(RRNodeClass: RRNode) {
|
>(RRNodeClass: RRNode) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return class BaseRRDocumentType
|
return class BaseRRDocumentType
|
||||||
extends RRNodeClass
|
extends RRNodeClass
|
||||||
@@ -410,6 +417,7 @@ export function BaseRRDocumentTypeImpl<
|
|||||||
export function BaseRRElementImpl<
|
export function BaseRRElementImpl<
|
||||||
RRNode extends ConstrainedConstructor<IRRNode>
|
RRNode extends ConstrainedConstructor<IRRNode>
|
||||||
>(RRNodeClass: RRNode) {
|
>(RRNodeClass: RRNode) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return class BaseRRElement extends RRNodeClass implements IRRElement {
|
return class BaseRRElement extends RRNodeClass implements IRRElement {
|
||||||
public readonly nodeType: number = NodeType.ELEMENT_NODE;
|
public readonly nodeType: number = NodeType.ELEMENT_NODE;
|
||||||
@@ -456,7 +464,7 @@ export function BaseRRElementImpl<
|
|||||||
|
|
||||||
public get style() {
|
public get style() {
|
||||||
const style = (this.attributes.style
|
const style = (this.attributes.style
|
||||||
? parseCSSText(this.attributes.style as string)
|
? parseCSSText(this.attributes.style)
|
||||||
: {}) as CSSStyleDeclaration;
|
: {}) as CSSStyleDeclaration;
|
||||||
const hyphenateRE = /\B([A-Z])/g;
|
const hyphenateRE = /\B([A-Z])/g;
|
||||||
style.setProperty = (
|
style.setProperty = (
|
||||||
@@ -546,7 +554,7 @@ export function BaseRRElementImpl<
|
|||||||
|
|
||||||
toString() {
|
toString() {
|
||||||
let attributeString = '';
|
let attributeString = '';
|
||||||
for (let attribute in this.attributes) {
|
for (const attribute in this.attributes) {
|
||||||
attributeString += `${attribute}="${this.attributes[attribute]}" `;
|
attributeString += `${attribute}="${this.attributes[attribute]}" `;
|
||||||
}
|
}
|
||||||
return `${this.tagName} ${attributeString}`;
|
return `${this.tagName} ${attributeString}`;
|
||||||
@@ -579,6 +587,7 @@ export function BaseRRMediaElementImpl<
|
|||||||
export function BaseRRTextImpl<RRNode extends ConstrainedConstructor<IRRNode>>(
|
export function BaseRRTextImpl<RRNode extends ConstrainedConstructor<IRRNode>>(
|
||||||
RRNodeClass: RRNode,
|
RRNodeClass: RRNode,
|
||||||
) {
|
) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return class BaseRRText extends RRNodeClass implements IRRText {
|
return class BaseRRText extends RRNodeClass implements IRRText {
|
||||||
public readonly nodeType: number = NodeType.TEXT_NODE;
|
public readonly nodeType: number = NodeType.TEXT_NODE;
|
||||||
@@ -608,6 +617,7 @@ export function BaseRRTextImpl<RRNode extends ConstrainedConstructor<IRRNode>>(
|
|||||||
export function BaseRRCommentImpl<
|
export function BaseRRCommentImpl<
|
||||||
RRNode extends ConstrainedConstructor<IRRNode>
|
RRNode extends ConstrainedConstructor<IRRNode>
|
||||||
>(RRNodeClass: RRNode) {
|
>(RRNodeClass: RRNode) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return class BaseRRComment extends RRNodeClass implements IRRComment {
|
return class BaseRRComment extends RRNodeClass implements IRRComment {
|
||||||
public readonly nodeType: number = NodeType.COMMENT_NODE;
|
public readonly nodeType: number = NodeType.COMMENT_NODE;
|
||||||
@@ -637,6 +647,7 @@ export function BaseRRCommentImpl<
|
|||||||
export function BaseRRCDATASectionImpl<
|
export function BaseRRCDATASectionImpl<
|
||||||
RRNode extends ConstrainedConstructor<IRRNode>
|
RRNode extends ConstrainedConstructor<IRRNode>
|
||||||
>(RRNodeClass: RRNode) {
|
>(RRNodeClass: RRNode) {
|
||||||
|
// eslint-disable-next-line @typescript-eslint/ban-ts-comment
|
||||||
// @ts-ignore
|
// @ts-ignore
|
||||||
return class BaseRRCDATASection
|
return class BaseRRCDATASection
|
||||||
extends RRNodeClass
|
extends RRNodeClass
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ export function parseCSSText(cssText: string): Record<string, string> {
|
|||||||
|
|
||||||
export function toCSSText(style: Record<string, string>): string {
|
export function toCSSText(style: Record<string, string>): string {
|
||||||
const properties = [];
|
const properties = [];
|
||||||
for (let name in style) {
|
for (const name in style) {
|
||||||
const value = style[name];
|
const value = style[name];
|
||||||
if (typeof value !== 'string') continue;
|
if (typeof value !== 'string') continue;
|
||||||
const normalizedName = hyphenate(name);
|
const normalizedName = hyphenate(name);
|
||||||
|
|||||||
@@ -226,7 +226,7 @@ export function buildFromNode(
|
|||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case NodeType.DOCUMENT_TYPE_NODE:
|
case NodeType.DOCUMENT_TYPE_NODE:
|
||||||
const documentType = (node as Node) as DocumentType;
|
const documentType = (node ) as DocumentType;
|
||||||
rrNode = rrdom.createDocumentType(
|
rrNode = rrdom.createDocumentType(
|
||||||
documentType.name,
|
documentType.name,
|
||||||
documentType.publicId,
|
documentType.publicId,
|
||||||
@@ -234,7 +234,7 @@ export function buildFromNode(
|
|||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
case NodeType.ELEMENT_NODE:
|
case NodeType.ELEMENT_NODE:
|
||||||
const elementNode = (node as Node) as HTMLElement;
|
const elementNode = (node ) as HTMLElement;
|
||||||
const tagName = getValidTagName(elementNode);
|
const tagName = getValidTagName(elementNode);
|
||||||
rrNode = rrdom.createElement(tagName);
|
rrNode = rrdom.createElement(tagName);
|
||||||
const rrElement = rrNode as IRRElement;
|
const rrElement = rrNode as IRRElement;
|
||||||
@@ -249,14 +249,14 @@ export function buildFromNode(
|
|||||||
*/
|
*/
|
||||||
break;
|
break;
|
||||||
case NodeType.TEXT_NODE:
|
case NodeType.TEXT_NODE:
|
||||||
rrNode = rrdom.createTextNode(((node as Node) as Text).textContent || '');
|
rrNode = rrdom.createTextNode(((node ) as Text).textContent || '');
|
||||||
break;
|
break;
|
||||||
case NodeType.CDATA_SECTION_NODE:
|
case NodeType.CDATA_SECTION_NODE:
|
||||||
rrNode = rrdom.createCDATASection(((node as Node) as CDATASection).data);
|
rrNode = rrdom.createCDATASection(((node ) as CDATASection).data);
|
||||||
break;
|
break;
|
||||||
case NodeType.COMMENT_NODE:
|
case NodeType.COMMENT_NODE:
|
||||||
rrNode = rrdom.createComment(
|
rrNode = rrdom.createComment(
|
||||||
((node as Node) as Comment).textContent || '',
|
((node ) as Comment).textContent || '',
|
||||||
);
|
);
|
||||||
break;
|
break;
|
||||||
// if node is a shadow root
|
// if node is a shadow root
|
||||||
@@ -316,9 +316,9 @@ export function buildFromDom(
|
|||||||
// if the node is a shadow dom
|
// if the node is a shadow dom
|
||||||
if (
|
if (
|
||||||
node.nodeType === NodeType.ELEMENT_NODE &&
|
node.nodeType === NodeType.ELEMENT_NODE &&
|
||||||
((node as Node) as HTMLElement).shadowRoot
|
((node ) as HTMLElement).shadowRoot
|
||||||
)
|
)
|
||||||
walk(((node as Node) as HTMLElement).shadowRoot!, rrNode);
|
walk(((node ) as HTMLElement).shadowRoot!, rrNode);
|
||||||
node.childNodes.forEach((childNode) => walk(childNode, rrNode));
|
node.childNodes.forEach((childNode) => walk(childNode, rrNode));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,25 +1,22 @@
|
|||||||
{
|
{
|
||||||
"extends": ["eslint:recommended", "plugin:@typescript-eslint/recommended"],
|
"extends": ["../../.eslintrc.js"],
|
||||||
"parser": "@typescript-eslint/parser",
|
|
||||||
"parserOptions": {
|
|
||||||
"ecmaVersion": 2019,
|
|
||||||
"sourceType": "module"
|
|
||||||
},
|
|
||||||
"rules": {
|
"rules": {
|
||||||
"require-jsdoc": "off",
|
"require-jsdoc": "off",
|
||||||
"arrow-parens": "off",
|
"arrow-parens": "off",
|
||||||
"object-curly-spacing": "off",
|
"object-curly-spacing": "off",
|
||||||
"indent": "off"
|
"indent": "off"
|
||||||
},
|
},
|
||||||
"env": {
|
"parserOptions": {
|
||||||
"es6": true,
|
"extraFileExtensions": [".svelte"]
|
||||||
"browser": true
|
|
||||||
},
|
},
|
||||||
"plugins": ["svelte3", "@typescript-eslint"],
|
"plugins": ["svelte3"],
|
||||||
"overrides": [
|
"overrides": [
|
||||||
{
|
{
|
||||||
"files": ["*.svelte"],
|
"files": ["*.svelte"],
|
||||||
"processor": "svelte3/svelte3"
|
"processor": "svelte3/svelte3"
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
|
"settings": {
|
||||||
|
"svelte3/typescript": true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -6,11 +6,8 @@
|
|||||||
"@rollup/plugin-node-resolve": "^13.2.1",
|
"@rollup/plugin-node-resolve": "^13.2.1",
|
||||||
"@rollup/plugin-typescript": "^8.3.2",
|
"@rollup/plugin-typescript": "^8.3.2",
|
||||||
"@types/offscreencanvas": "^2019.6.4",
|
"@types/offscreencanvas": "^2019.6.4",
|
||||||
"@typescript-eslint/eslint-plugin": "^3.7.0",
|
"eslint-config-google": "^0.14.0",
|
||||||
"@typescript-eslint/parser": "^3.7.0",
|
"eslint-plugin-svelte3": "^4.0.0",
|
||||||
"eslint": "^7.5.0",
|
|
||||||
"eslint-config-google": "^0.11.0",
|
|
||||||
"eslint-plugin-svelte3": "^2.7.3",
|
|
||||||
"postcss-easy-import": "^3.0.0",
|
"postcss-easy-import": "^3.0.0",
|
||||||
"rollup": "^2.71.1",
|
"rollup": "^2.71.1",
|
||||||
"rollup-plugin-css-only": "^3.1.0",
|
"rollup-plugin-css-only": "^3.1.0",
|
||||||
@@ -35,7 +32,8 @@
|
|||||||
"prepublishOnly": "yarn build",
|
"prepublishOnly": "yarn build",
|
||||||
"start": "sirv public",
|
"start": "sirv public",
|
||||||
"validate": "svelte-check",
|
"validate": "svelte-check",
|
||||||
"prepublish": "yarn build"
|
"prepublish": "yarn build",
|
||||||
|
"lint": "yarn eslint src/**/*.ts"
|
||||||
},
|
},
|
||||||
"description": "rrweb's replayer UI",
|
"description": "rrweb's replayer UI",
|
||||||
"main": "lib/index.js",
|
"main": "lib/index.js",
|
||||||
|
|||||||
@@ -186,20 +186,20 @@
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const triggerUpdateMeta = () => {
|
export const triggerUpdateMeta = () => {
|
||||||
Promise.resolve().then(() => {
|
return Promise.resolve().then(() => {
|
||||||
meta = replayer.getMetaData();
|
meta = replayer.getMetaData();
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
onMount(() => {
|
onMount(() => {
|
||||||
playerState = replayer.service.state.value as typeof playerState;
|
playerState = replayer.service.state.value;
|
||||||
speedState = replayer.speedService.state.value as typeof speedState;
|
speedState = replayer.speedService.state.value ;
|
||||||
replayer.on(
|
replayer.on(
|
||||||
'state-change',
|
'state-change',
|
||||||
(states: { player?: PlayerMachineState; speed?: SpeedMachineState }) => {
|
(states: { player?: PlayerMachineState; speed?: SpeedMachineState }) => {
|
||||||
const { player, speed } = states;
|
const { player, speed } = states;
|
||||||
if (player?.value && playerState !== player.value) {
|
if (player?.value && playerState !== player.value) {
|
||||||
playerState = player.value as typeof playerState;
|
playerState = player.value ;
|
||||||
switch (playerState) {
|
switch (playerState) {
|
||||||
case 'playing':
|
case 'playing':
|
||||||
loopTimer();
|
loopTimer();
|
||||||
@@ -212,7 +212,7 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (speed?.value && speedState !== speed.value) {
|
if (speed?.value && speedState !== speed.value) {
|
||||||
speedState = speed.value as typeof speedState;
|
speedState = speed.value ;
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
@@ -338,7 +338,7 @@
|
|||||||
class="rr-progress"
|
class="rr-progress"
|
||||||
class:disabled={speedState === 'skipping'}
|
class:disabled={speedState === 'skipping'}
|
||||||
bind:this={progress}
|
bind:this={progress}
|
||||||
on:click={(event) => handleProgressClick(event)}>
|
on:click={handleProgressClick}>
|
||||||
<div
|
<div
|
||||||
class="rr-progress__step"
|
class="rr-progress__step"
|
||||||
bind:this={step}
|
bind:this={step}
|
||||||
|
|||||||
@@ -12,14 +12,14 @@
|
|||||||
} from './utils';
|
} from './utils';
|
||||||
import Controller from './Controller.svelte';
|
import Controller from './Controller.svelte';
|
||||||
|
|
||||||
export let width: number = 1024;
|
export let width = 1024;
|
||||||
export let height: number = 576;
|
export let height = 576;
|
||||||
export let events: eventWithTime[] = [];
|
export let events: eventWithTime[] = [];
|
||||||
export let skipInactive: boolean = true;
|
export let skipInactive = true;
|
||||||
export let autoPlay: boolean = true;
|
export let autoPlay = true;
|
||||||
export let speedOption: number[] = [1, 2, 4, 8];
|
export let speedOption: number[] = [1, 2, 4, 8];
|
||||||
export let speed: number = 1;
|
export let speed = 1;
|
||||||
export let showController: boolean = true;
|
export let showController = true;
|
||||||
export let tags: Record<string, string> = {};
|
export let tags: Record<string, string> = {};
|
||||||
|
|
||||||
let replayer: Replayer;
|
let replayer: Replayer;
|
||||||
|
|||||||
@@ -28,7 +28,7 @@ function padZero(num: number, len = 2): string {
|
|||||||
const threshold = Math.pow(10, len - 1);
|
const threshold = Math.pow(10, len - 1);
|
||||||
if (num < threshold) {
|
if (num < threshold) {
|
||||||
while (String(threshold).length > str.length) {
|
while (String(threshold).length > str.length) {
|
||||||
str = '0' + num;
|
str = `0${num}`;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return str;
|
return str;
|
||||||
|
|||||||
@@ -11,7 +11,8 @@
|
|||||||
"bundle:es-only": "cross-env ES_ONLY=true rollup --config",
|
"bundle:es-only": "cross-env ES_ONLY=true rollup --config",
|
||||||
"dev": "yarn bundle:es-only --watch",
|
"dev": "yarn bundle:es-only --watch",
|
||||||
"typings": "tsc -d --declarationDir typings",
|
"typings": "tsc -d --declarationDir typings",
|
||||||
"prepublish": "npm run typings && npm run bundle"
|
"prepublish": "npm run typings && npm run bundle",
|
||||||
|
"lint": "yarn eslint src"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -55,7 +56,6 @@
|
|||||||
"ts-jest": "^27.0.5",
|
"ts-jest": "^27.0.5",
|
||||||
"ts-node": "^7.0.1",
|
"ts-node": "^7.0.1",
|
||||||
"tslib": "^1.9.3",
|
"tslib": "^1.9.3",
|
||||||
"tslint": "^4.5.1",
|
|
||||||
"typescript": "^3.9.7"
|
"typescript": "^3.9.7"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -242,7 +242,7 @@ export function parse(css: string, options: ParserOptions = {}) {
|
|||||||
if (lines) {
|
if (lines) {
|
||||||
lineno += lines.length;
|
lineno += lines.length;
|
||||||
}
|
}
|
||||||
let i = str.lastIndexOf('\n');
|
const i = str.lastIndexOf('\n');
|
||||||
column = i === -1 ? column + str.length : str.length - i;
|
column = i === -1 ? column + str.length : str.length - i;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -457,7 +457,7 @@ export function parse(css: string, options: ParserOptions = {}) {
|
|||||||
const pos = position();
|
const pos = position();
|
||||||
|
|
||||||
// prop
|
// prop
|
||||||
let propMatch = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
|
const propMatch = match(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/);
|
||||||
if (!propMatch) {
|
if (!propMatch) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -148,7 +148,8 @@ function buildNode(
|
|||||||
}
|
}
|
||||||
let value = n.attributes[name];
|
let value = n.attributes[name];
|
||||||
if (tagName === 'option' && name === 'selected' && value === false) {
|
if (tagName === 'option' && name === 'selected' && value === false) {
|
||||||
// legacy fix (TODO: if `value === false` can be generated for other attrs, should we also omit those other attrs from build?)
|
// legacy fix (TODO: if `value === false` can be generated for other attrs,
|
||||||
|
// should we also omit those other attrs from build ?)
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
value =
|
value =
|
||||||
|
|||||||
@@ -154,7 +154,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
|
|||||||
|
|
||||||
function collectCharacters(regEx: RegExp) {
|
function collectCharacters(regEx: RegExp) {
|
||||||
let chars: string;
|
let chars: string;
|
||||||
let match = regEx.exec(attributeValue.substring(pos));
|
const match = regEx.exec(attributeValue.substring(pos));
|
||||||
if (match) {
|
if (match) {
|
||||||
chars = match[0];
|
chars = match[0];
|
||||||
pos += chars.length;
|
pos += chars.length;
|
||||||
@@ -163,7 +163,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
|
|||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
|
|
||||||
let output = [];
|
const output = [];
|
||||||
while (true) {
|
while (true) {
|
||||||
collectCharacters(SRCSET_COMMAS_OR_SPACES);
|
collectCharacters(SRCSET_COMMAS_OR_SPACES);
|
||||||
if (pos >= attributeValue.length) {
|
if (pos >= attributeValue.length) {
|
||||||
@@ -182,7 +182,7 @@ function getAbsoluteSrcsetString(doc: Document, attributeValue: string) {
|
|||||||
url = absoluteToDoc(doc, url);
|
url = absoluteToDoc(doc, url);
|
||||||
let inParens = false;
|
let inParens = false;
|
||||||
while (true) {
|
while (true) {
|
||||||
let c = attributeValue.charAt(pos);
|
const c = attributeValue.charAt(pos);
|
||||||
if (c === '') {
|
if (c === '') {
|
||||||
output.push((url + descriptorsStr).trim());
|
output.push((url + descriptorsStr).trim());
|
||||||
break;
|
break;
|
||||||
@@ -462,7 +462,7 @@ function serializeNode(
|
|||||||
});
|
});
|
||||||
let cssText: string | null = null;
|
let cssText: string | null = null;
|
||||||
if (stylesheet) {
|
if (stylesheet) {
|
||||||
cssText = getCssRulesString(stylesheet as CSSStyleSheet);
|
cssText = getCssRulesString(stylesheet );
|
||||||
}
|
}
|
||||||
if (cssText) {
|
if (cssText) {
|
||||||
delete attributes.rel;
|
delete attributes.rel;
|
||||||
|
|||||||
@@ -1,21 +0,0 @@
|
|||||||
{
|
|
||||||
"defaultSeverity": "error",
|
|
||||||
"extends": ["tslint:recommended"],
|
|
||||||
"jsRules": {},
|
|
||||||
"rules": {
|
|
||||||
"no-any": true,
|
|
||||||
"quotemark": [true, "single"],
|
|
||||||
"ordered-imports": false,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"no-unused-variable": true,
|
|
||||||
"object-literal-key-quotes": false,
|
|
||||||
"variable-name": [
|
|
||||||
true,
|
|
||||||
"ban-keywords",
|
|
||||||
"check-format",
|
|
||||||
"allow-leading-underscore"
|
|
||||||
],
|
|
||||||
"arrow-parens": false
|
|
||||||
},
|
|
||||||
"rulesDirectory": []
|
|
||||||
}
|
|
||||||
@@ -14,7 +14,8 @@
|
|||||||
"bundle": "rollup --config",
|
"bundle": "rollup --config",
|
||||||
"typings": "tsc -d --declarationDir typings",
|
"typings": "tsc -d --declarationDir typings",
|
||||||
"check-types": "tsc -noEmit",
|
"check-types": "tsc -noEmit",
|
||||||
"prepublish": "npm run typings && npm run bundle"
|
"prepublish": "npm run typings && npm run bundle",
|
||||||
|
"lint": "yarn eslint src"
|
||||||
},
|
},
|
||||||
"repository": {
|
"repository": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
@@ -70,7 +71,6 @@
|
|||||||
"ts-jest": "^27.1.3",
|
"ts-jest": "^27.1.3",
|
||||||
"ts-node": "^10.7.0",
|
"ts-node": "^10.7.0",
|
||||||
"tslib": "^2.3.1",
|
"tslib": "^2.3.1",
|
||||||
"tslint": "^6.1.3",
|
|
||||||
"typescript": "^4.6.2"
|
"typescript": "^4.6.2"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
/* tslint:disable: no-console */
|
/* eslint:disable: no-console */
|
||||||
|
|
||||||
const fs = require('fs');
|
const fs = require('fs');
|
||||||
const path = require('path');
|
const path = require('path');
|
||||||
@@ -13,11 +13,11 @@ function getCode() {
|
|||||||
return fs.readFileSync(bundlePath, 'utf8');
|
return fs.readFileSync(bundlePath, 'utf8');
|
||||||
}
|
}
|
||||||
|
|
||||||
(async () => {
|
void (async () => {
|
||||||
const code = getCode();
|
const code = getCode();
|
||||||
let events = [];
|
let events = [];
|
||||||
|
|
||||||
start();
|
await start();
|
||||||
|
|
||||||
const fakeGoto = async (page, url) => {
|
const fakeGoto = async (page, url) => {
|
||||||
const intercept = async (request) => {
|
const intercept = async (request) => {
|
||||||
|
|||||||
@@ -22,14 +22,14 @@ function pathToSelector(node: HTMLElement): string | '' {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
name = name.toLowerCase();
|
name = name.toLowerCase();
|
||||||
let parent = node.parentElement;
|
const parent = node.parentElement;
|
||||||
|
|
||||||
let domSiblings = [];
|
const domSiblings = [];
|
||||||
|
|
||||||
if (parent.children && parent.children.length > 0) {
|
if (parent.children && parent.children.length > 0) {
|
||||||
// tslint:disable-next-line:prefer-for-of
|
// tslint:disable-next-line:prefer-for-of
|
||||||
for (let i = 0; i < parent.children.length; i++) {
|
for (let i = 0; i < parent.children.length; i++) {
|
||||||
let sibling = parent.children[i];
|
const sibling = parent.children[i];
|
||||||
if (sibling.localName && sibling.localName.toLowerCase) {
|
if (sibling.localName && sibling.localName.toLowerCase) {
|
||||||
if (sibling.localName.toLowerCase() === name) {
|
if (sibling.localName.toLowerCase() === name) {
|
||||||
domSiblings.push(sibling);
|
domSiblings.push(sibling);
|
||||||
|
|||||||
@@ -123,8 +123,8 @@ const moveKey = (id: number, parentId: number) => `${id}@${parentId}`;
|
|||||||
* controls behaviour of a MutationObserver
|
* controls behaviour of a MutationObserver
|
||||||
*/
|
*/
|
||||||
export default class MutationBuffer {
|
export default class MutationBuffer {
|
||||||
private frozen: boolean = false;
|
private frozen = false;
|
||||||
private locked: boolean = false;
|
private locked = false;
|
||||||
|
|
||||||
private texts: textCursor[] = [];
|
private texts: textCursor[] = [];
|
||||||
private attributes: attributeCursor[] = [];
|
private attributes: attributeCursor[] = [];
|
||||||
@@ -597,7 +597,7 @@ export default class MutationBuffer {
|
|||||||
// if this node is blocked `serializeNode` will turn it into a placeholder element
|
// if this node is blocked `serializeNode` will turn it into a placeholder element
|
||||||
// but we have to remove it's children otherwise they will be added as placeholders too
|
// but we have to remove it's children otherwise they will be added as placeholders too
|
||||||
if (!isBlocked(n, this.blockClass))
|
if (!isBlocked(n, this.blockClass))
|
||||||
(n as Node).childNodes.forEach((childN) => this.genAdds(childN));
|
(n ).childNodes.forEach((childN) => this.genAdds(childN));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -549,8 +549,8 @@ function initStyleSheetObserver(
|
|||||||
|
|
||||||
Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
|
Object.entries(supportedNestedCSSRuleTypes).forEach(([typeKey, type]) => {
|
||||||
unmodifiedFunctions[typeKey] = {
|
unmodifiedFunctions[typeKey] = {
|
||||||
insertRule: (type as GroupingCSSRuleTypes).prototype.insertRule,
|
insertRule: (type ).prototype.insertRule,
|
||||||
deleteRule: (type as GroupingCSSRuleTypes).prototype.deleteRule,
|
deleteRule: (type ).prototype.deleteRule,
|
||||||
};
|
};
|
||||||
|
|
||||||
type.prototype.insertRule = function (rule: string, index?: number) {
|
type.prototype.insertRule = function (rule: string, index?: number) {
|
||||||
|
|||||||
@@ -30,8 +30,8 @@ export class CanvasManager {
|
|||||||
|
|
||||||
private mutationCb: canvasMutationCallback;
|
private mutationCb: canvasMutationCallback;
|
||||||
private resetObservers?: listenerHandler;
|
private resetObservers?: listenerHandler;
|
||||||
private frozen: boolean = false;
|
private frozen = false;
|
||||||
private locked: boolean = false;
|
private locked = false;
|
||||||
|
|
||||||
public reset() {
|
public reset() {
|
||||||
this.pendingCanvasMutations.clear();
|
this.pendingCanvasMutations.clear();
|
||||||
|
|||||||
@@ -19,7 +19,7 @@ export default function initCanvasContextObserver(
|
|||||||
) {
|
) {
|
||||||
if (!isBlocked(this, blockClass)) {
|
if (!isBlocked(this, blockClass)) {
|
||||||
if (!('__context' in this))
|
if (!('__context' in this))
|
||||||
(this as ICanvas).__context = contextType;
|
(this ).__context = contextType;
|
||||||
}
|
}
|
||||||
return original.apply(this, [contextType, ...args]);
|
return original.apply(this, [contextType, ...args]);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -31,8 +31,8 @@ function patchGLPrototype(
|
|||||||
return function (this: typeof prototype, ...args: Array<unknown>) {
|
return function (this: typeof prototype, ...args: Array<unknown>) {
|
||||||
const result = original.apply(this, args);
|
const result = original.apply(this, args);
|
||||||
saveWebGLVar(result, win, prototype);
|
saveWebGLVar(result, win, prototype);
|
||||||
if (!isBlocked(this.canvas as HTMLCanvasElement, blockClass)) {
|
if (!isBlocked(this.canvas , blockClass)) {
|
||||||
const id = mirror.getId(this.canvas as HTMLCanvasElement);
|
const id = mirror.getId(this.canvas );
|
||||||
|
|
||||||
const recordArgs = serializeArgs([...args], win, prototype);
|
const recordArgs = serializeArgs([...args], win, prototype);
|
||||||
const mutation: canvasMutationWithType = {
|
const mutation: canvasMutationWithType = {
|
||||||
@@ -41,7 +41,7 @@ function patchGLPrototype(
|
|||||||
args: recordArgs,
|
args: recordArgs,
|
||||||
};
|
};
|
||||||
// TODO: this could potentially also be an OffscreenCanvas as well as HTMLCanvasElement
|
// TODO: this could potentially also be an OffscreenCanvas as well as HTMLCanvasElement
|
||||||
cb(this.canvas as HTMLCanvasElement, mutation);
|
cb(this.canvas , mutation);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ export default async function canvasMutation({
|
|||||||
errorHandler: Replayer['warnCanvasMutationFailed'];
|
errorHandler: Replayer['warnCanvasMutationFailed'];
|
||||||
}): Promise<void> {
|
}): Promise<void> {
|
||||||
try {
|
try {
|
||||||
let precomputedMutation: canvasMutationParam =
|
const precomputedMutation: canvasMutationParam =
|
||||||
canvasEventMap.get(event) || mutation;
|
canvasEventMap.get(event) || mutation;
|
||||||
|
|
||||||
const commands: canvasMutationCommand[] =
|
const commands: canvasMutationCommand[] =
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ function getContext(
|
|||||||
try {
|
try {
|
||||||
if (type === CanvasContext.WebGL) {
|
if (type === CanvasContext.WebGL) {
|
||||||
return (target.getContext('webgl')! ||
|
return (target.getContext('webgl')! ||
|
||||||
target.getContext('experimental-webgl')) as WebGLRenderingContext;
|
target.getContext('experimental-webgl'));
|
||||||
}
|
}
|
||||||
return target.getContext('webgl2')!;
|
return target.getContext('webgl2')!;
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
|
|||||||
@@ -350,7 +350,7 @@ export class Replayer {
|
|||||||
this.speedService.send({
|
this.speedService.send({
|
||||||
type: 'SET_SPEED',
|
type: 'SET_SPEED',
|
||||||
payload: {
|
payload: {
|
||||||
speed: config.speed!,
|
speed: config.speed,
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -478,7 +478,7 @@ export class Replayer {
|
|||||||
private setupDom() {
|
private setupDom() {
|
||||||
this.wrapper = document.createElement('div');
|
this.wrapper = document.createElement('div');
|
||||||
this.wrapper.classList.add('replayer-wrapper');
|
this.wrapper.classList.add('replayer-wrapper');
|
||||||
this.config.root!.appendChild(this.wrapper);
|
this.config.root.appendChild(this.wrapper);
|
||||||
|
|
||||||
this.mouse = document.createElement('div');
|
this.mouse = document.createElement('div');
|
||||||
this.mouse.classList.add('replayer-mouse');
|
this.mouse.classList.add('replayer-mouse');
|
||||||
@@ -600,7 +600,7 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
if (this.config.skipInactive && !this.nextUserInteractionEvent) {
|
if (this.config.skipInactive && !this.nextUserInteractionEvent) {
|
||||||
for (const _event of this.service.state.context.events) {
|
for (const _event of this.service.state.context.events) {
|
||||||
if (_event.timestamp! <= event.timestamp!) {
|
if (_event.timestamp <= event.timestamp) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (this.isUserInteraction(_event)) {
|
if (this.isUserInteraction(_event)) {
|
||||||
@@ -643,7 +643,7 @@ export class Replayer {
|
|||||||
this.service.send({ type: 'CAST_EVENT', payload: { event } });
|
this.service.send({ type: 'CAST_EVENT', payload: { event } });
|
||||||
|
|
||||||
// events are kept sorted by timestamp, check if this is the last event
|
// events are kept sorted by timestamp, check if this is the last event
|
||||||
let last_index = this.service.state.context.events.length - 1;
|
const last_index = this.service.state.context.events.length - 1;
|
||||||
if (event === this.service.state.context.events[last_index]) {
|
if (event === this.service.state.context.events[last_index]) {
|
||||||
const finish = () => {
|
const finish = () => {
|
||||||
if (last_index < this.service.state.context.events.length - 1) {
|
if (last_index < this.service.state.context.events.length - 1) {
|
||||||
@@ -675,7 +675,7 @@ export class Replayer {
|
|||||||
|
|
||||||
private rebuildFullSnapshot(
|
private rebuildFullSnapshot(
|
||||||
event: fullSnapshotEvent & { timestamp: number },
|
event: fullSnapshotEvent & { timestamp: number },
|
||||||
isSync: boolean = false,
|
isSync = false,
|
||||||
) {
|
) {
|
||||||
if (!this.iframe.contentDocument) {
|
if (!this.iframe.contentDocument) {
|
||||||
return console.warn('Looks like your replayer has been destroyed.');
|
return console.warn('Looks like your replayer has been destroyed.');
|
||||||
@@ -731,7 +731,7 @@ export class Replayer {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
if (this.usingVirtualDom) {
|
if (this.usingVirtualDom) {
|
||||||
const styleEl = this.virtualDom.createElement('style') as RRStyleElement;
|
const styleEl = this.virtualDom.createElement('style') ;
|
||||||
this.virtualDom.mirror.add(
|
this.virtualDom.mirror.add(
|
||||||
styleEl,
|
styleEl,
|
||||||
getDefaultSN(styleEl, this.virtualDom.unserializedId),
|
getDefaultSN(styleEl, this.virtualDom.unserializedId),
|
||||||
@@ -752,7 +752,7 @@ export class Replayer {
|
|||||||
head as HTMLHeadElement,
|
head as HTMLHeadElement,
|
||||||
);
|
);
|
||||||
for (let idx = 0; idx < injectStylesRules.length; idx++) {
|
for (let idx = 0; idx < injectStylesRules.length; idx++) {
|
||||||
(styleEl.sheet! as CSSStyleSheet).insertRule(
|
(styleEl.sheet! ).insertRule(
|
||||||
injectStylesRules[idx],
|
injectStylesRules[idx],
|
||||||
idx,
|
idx,
|
||||||
);
|
);
|
||||||
@@ -1210,7 +1210,7 @@ export class Replayer {
|
|||||||
if (!target) {
|
if (!target) {
|
||||||
return this.debugNodeNotFound(d, d.id);
|
return this.debugNodeNotFound(d, d.id);
|
||||||
}
|
}
|
||||||
const styleSheet = ((target as Node) as HTMLStyleElement).sheet!;
|
const styleSheet = ((target ) as HTMLStyleElement).sheet!;
|
||||||
d.adds?.forEach(({ rule, index: nestedIndex }) => {
|
d.adds?.forEach(({ rule, index: nestedIndex }) => {
|
||||||
try {
|
try {
|
||||||
if (Array.isArray(nestedIndex)) {
|
if (Array.isArray(nestedIndex)) {
|
||||||
@@ -1383,7 +1383,7 @@ export class Replayer {
|
|||||||
type TNode = typeof mirror extends Mirror ? Node : RRNode;
|
type TNode = typeof mirror extends Mirror ? Node : RRNode;
|
||||||
|
|
||||||
d.removes.forEach((mutation) => {
|
d.removes.forEach((mutation) => {
|
||||||
let target = mirror.getNode(mutation.id);
|
const target = mirror.getNode(mutation.id);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
if (d.removes.find((r) => r.id === mutation.parentId)) {
|
if (d.removes.find((r) => r.id === mutation.parentId)) {
|
||||||
// no need to warn, parent was already removed
|
// no need to warn, parent was already removed
|
||||||
@@ -1612,7 +1612,7 @@ export class Replayer {
|
|||||||
appendNode(mutation);
|
appendNode(mutation);
|
||||||
});
|
});
|
||||||
|
|
||||||
let startTime = Date.now();
|
const startTime = Date.now();
|
||||||
while (queue.length) {
|
while (queue.length) {
|
||||||
// transform queue to resolve tree
|
// transform queue to resolve tree
|
||||||
const resolveTrees = queueToResolveTrees(queue);
|
const resolveTrees = queueToResolveTrees(queue);
|
||||||
@@ -1625,7 +1625,7 @@ export class Replayer {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
for (const tree of resolveTrees) {
|
for (const tree of resolveTrees) {
|
||||||
let parent = mirror.getNode(tree.value.parentId);
|
const parent = mirror.getNode(tree.value.parentId);
|
||||||
if (!parent) {
|
if (!parent) {
|
||||||
this.debug(
|
this.debug(
|
||||||
'Drop resolve tree since there is no parent for the root node.',
|
'Drop resolve tree since there is no parent for the root node.',
|
||||||
@@ -1644,7 +1644,7 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
|
|
||||||
uniqueTextMutations(d.texts).forEach((mutation) => {
|
uniqueTextMutations(d.texts).forEach((mutation) => {
|
||||||
let target = mirror.getNode(mutation.id);
|
const target = mirror.getNode(mutation.id);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
if (d.removes.find((r) => r.id === mutation.id)) {
|
if (d.removes.find((r) => r.id === mutation.id)) {
|
||||||
// no need to warn, element was already removed
|
// no need to warn, element was already removed
|
||||||
@@ -1664,7 +1664,7 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
d.attributes.forEach((mutation) => {
|
d.attributes.forEach((mutation) => {
|
||||||
let target = mirror.getNode(mutation.id);
|
const target = mirror.getNode(mutation.id);
|
||||||
if (!target) {
|
if (!target) {
|
||||||
if (d.removes.find((r) => r.id === mutation.id)) {
|
if (d.removes.find((r) => r.id === mutation.id)) {
|
||||||
// no need to warn, element was already removed
|
// no need to warn, element was already removed
|
||||||
@@ -1692,9 +1692,9 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (attributeName === 'style') {
|
} else if (attributeName === 'style') {
|
||||||
let styleValues = value as styleAttributeValue;
|
const styleValues = value ;
|
||||||
const targetEl = target as HTMLElement | RRElement;
|
const targetEl = target as HTMLElement | RRElement;
|
||||||
for (var s in styleValues) {
|
for (const s in styleValues) {
|
||||||
if (styleValues[s] === false) {
|
if (styleValues[s] === false) {
|
||||||
targetEl.style.removeProperty(s);
|
targetEl.style.removeProperty(s);
|
||||||
} else if (styleValues[s] instanceof Array) {
|
} else if (styleValues[s] instanceof Array) {
|
||||||
@@ -1772,7 +1772,7 @@ export class Replayer {
|
|||||||
const previousInMap = previousId && map[previousId];
|
const previousInMap = previousId && map[previousId];
|
||||||
const nextInMap = nextId && map[nextId];
|
const nextInMap = nextId && map[nextId];
|
||||||
if (previousInMap) {
|
if (previousInMap) {
|
||||||
const { node, mutation } = previousInMap as missingNode;
|
const { node, mutation } = previousInMap ;
|
||||||
parent.insertBefore(node as Node & RRNode, target as Node & RRNode);
|
parent.insertBefore(node as Node & RRNode, target as Node & RRNode);
|
||||||
delete map[mutation.node.id];
|
delete map[mutation.node.id];
|
||||||
delete this.legacy_missingNodeRetryMap[mutation.node.id];
|
delete this.legacy_missingNodeRetryMap[mutation.node.id];
|
||||||
@@ -1781,7 +1781,7 @@ export class Replayer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (nextInMap) {
|
if (nextInMap) {
|
||||||
const { node, mutation } = nextInMap as missingNode;
|
const { node, mutation } = nextInMap ;
|
||||||
parent.insertBefore(
|
parent.insertBefore(
|
||||||
node as Node & RRNode,
|
node as Node & RRNode,
|
||||||
target.nextSibling as Node & RRNode,
|
target.nextSibling as Node & RRNode,
|
||||||
|
|||||||
@@ -248,7 +248,7 @@ export function createPlayerService(
|
|||||||
let insertionIndex = -1;
|
let insertionIndex = -1;
|
||||||
let start = 0;
|
let start = 0;
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
let mid = Math.floor((start + end) / 2);
|
const mid = Math.floor((start + end) / 2);
|
||||||
if (events[mid].timestamp <= event.timestamp) {
|
if (events[mid].timestamp <= event.timestamp) {
|
||||||
start = mid + 1;
|
start = mid + 1;
|
||||||
} else {
|
} else {
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// globals
|
// globals
|
||||||
var Element = w.HTMLElement || w.Element;
|
const Element = w.HTMLElement || w.Element;
|
||||||
var SCROLL_TIME = 468;
|
const SCROLL_TIME = 468;
|
||||||
|
|
||||||
// object gathering original scroll methods
|
// object gathering original scroll methods
|
||||||
var original = {
|
const original = {
|
||||||
scroll: w.scroll || w.scrollTo,
|
scroll: w.scroll || w.scrollTo,
|
||||||
scrollBy: w.scrollBy,
|
scrollBy: w.scrollBy,
|
||||||
elementScroll: Element.prototype.scroll || scrollElement,
|
elementScroll: Element.prototype.scroll || scrollElement,
|
||||||
@@ -27,7 +27,7 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
};
|
};
|
||||||
|
|
||||||
// define timing method
|
// define timing method
|
||||||
var now =
|
const now =
|
||||||
w.performance && w.performance.now
|
w.performance && w.performance.now
|
||||||
? w.performance.now.bind(w.performance)
|
? w.performance.now.bind(w.performance)
|
||||||
: Date.now;
|
: Date.now;
|
||||||
@@ -39,7 +39,7 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
function isMicrosoftBrowser(userAgent) {
|
function isMicrosoftBrowser(userAgent) {
|
||||||
var userAgentPatterns = ['MSIE ', 'Trident/', 'Edge/'];
|
const userAgentPatterns = ['MSIE ', 'Trident/', 'Edge/'];
|
||||||
|
|
||||||
return new RegExp(userAgentPatterns.join('|')).test(userAgent);
|
return new RegExp(userAgentPatterns.join('|')).test(userAgent);
|
||||||
}
|
}
|
||||||
@@ -49,7 +49,7 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
* rounding up scrollHeight and scrollWidth causing false positives
|
* rounding up scrollHeight and scrollWidth causing false positives
|
||||||
* on hasScrollableSpace
|
* on hasScrollableSpace
|
||||||
*/
|
*/
|
||||||
var ROUNDING_TOLERANCE = isMicrosoftBrowser(w.navigator.userAgent) ? 1 : 0;
|
const ROUNDING_TOLERANCE = isMicrosoftBrowser(w.navigator.userAgent) ? 1 : 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* changes scroll position inside an element
|
* changes scroll position inside an element
|
||||||
@@ -130,7 +130,7 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
function canOverflow(el, axis) {
|
function canOverflow(el, axis) {
|
||||||
var overflowValue = w.getComputedStyle(el, null)['overflow' + axis];
|
const overflowValue = w.getComputedStyle(el, null)['overflow' + axis];
|
||||||
|
|
||||||
return overflowValue === 'auto' || overflowValue === 'scroll';
|
return overflowValue === 'auto' || overflowValue === 'scroll';
|
||||||
}
|
}
|
||||||
@@ -143,8 +143,8 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
* @returns {Boolean}
|
* @returns {Boolean}
|
||||||
*/
|
*/
|
||||||
function isScrollable(el) {
|
function isScrollable(el) {
|
||||||
var isScrollableY = hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y');
|
const isScrollableY = hasScrollableSpace(el, 'Y') && canOverflow(el, 'Y');
|
||||||
var isScrollableX = hasScrollableSpace(el, 'X') && canOverflow(el, 'X');
|
const isScrollableX = hasScrollableSpace(el, 'X') && canOverflow(el, 'X');
|
||||||
|
|
||||||
return isScrollableY || isScrollableX;
|
return isScrollableY || isScrollableX;
|
||||||
}
|
}
|
||||||
@@ -170,11 +170,11 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
function step(context) {
|
function step(context) {
|
||||||
var time = now();
|
const time = now();
|
||||||
var value;
|
let value;
|
||||||
var currentX;
|
let currentX;
|
||||||
var currentY;
|
let currentY;
|
||||||
var elapsed = (time - context.startTime) / SCROLL_TIME;
|
let elapsed = (time - context.startTime) / SCROLL_TIME;
|
||||||
|
|
||||||
// avoid elapsed times higher than one
|
// avoid elapsed times higher than one
|
||||||
elapsed = elapsed > 1 ? 1 : elapsed;
|
elapsed = elapsed > 1 ? 1 : elapsed;
|
||||||
@@ -202,11 +202,11 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
* @returns {undefined}
|
* @returns {undefined}
|
||||||
*/
|
*/
|
||||||
function smoothScroll(el, x, y) {
|
function smoothScroll(el, x, y) {
|
||||||
var scrollable;
|
let scrollable;
|
||||||
var startX;
|
let startX;
|
||||||
var startY;
|
let startY;
|
||||||
var method;
|
let method;
|
||||||
var startTime = now();
|
const startTime = now();
|
||||||
|
|
||||||
// define scroll context
|
// define scroll context
|
||||||
if (el === d.body) {
|
if (el === d.body) {
|
||||||
@@ -342,8 +342,8 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var left = arguments[0].left;
|
const left = arguments[0].left;
|
||||||
var top = arguments[0].top;
|
const top = arguments[0].top;
|
||||||
|
|
||||||
// LET THE SMOOTHNESS BEGIN!
|
// LET THE SMOOTHNESS BEGIN!
|
||||||
smoothScroll.call(
|
smoothScroll.call(
|
||||||
@@ -396,9 +396,9 @@ export function polyfill(w: Window = window, d = document) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// LET THE SMOOTHNESS BEGIN!
|
// LET THE SMOOTHNESS BEGIN!
|
||||||
var scrollableParent = findScrollableParent(this);
|
const scrollableParent = findScrollableParent(this);
|
||||||
var parentRects = scrollableParent.getBoundingClientRect();
|
const parentRects = scrollableParent.getBoundingClientRect();
|
||||||
var clientRects = this.getBoundingClientRect();
|
const clientRects = this.getBoundingClientRect();
|
||||||
|
|
||||||
if (scrollableParent !== d.body) {
|
if (scrollableParent !== d.body) {
|
||||||
// reveal element inside parent
|
// reveal element inside parent
|
||||||
|
|||||||
@@ -6,7 +6,7 @@ import {
|
|||||||
} from '../types';
|
} from '../types';
|
||||||
|
|
||||||
export class Timer {
|
export class Timer {
|
||||||
public timeOffset: number = 0;
|
public timeOffset = 0;
|
||||||
public speed: number;
|
public speed: number;
|
||||||
|
|
||||||
private actions: actionWithDelay[];
|
private actions: actionWithDelay[];
|
||||||
@@ -83,7 +83,7 @@ export class Timer {
|
|||||||
let start = 0;
|
let start = 0;
|
||||||
let end = this.actions.length - 1;
|
let end = this.actions.length - 1;
|
||||||
while (start <= end) {
|
while (start <= end) {
|
||||||
let mid = Math.floor((start + end) / 2);
|
const mid = Math.floor((start + end) / 2);
|
||||||
if (this.actions[mid].delay < action.delay) {
|
if (this.actions[mid].delay < action.delay) {
|
||||||
start = mid + 1;
|
start = mid + 1;
|
||||||
} else if (this.actions[mid].delay > action.delay) {
|
} else if (this.actions[mid].delay > action.delay) {
|
||||||
|
|||||||
@@ -70,15 +70,14 @@ export function throttle<T>(
|
|||||||
) {
|
) {
|
||||||
let timeout: ReturnType<typeof setTimeout> | null = null;
|
let timeout: ReturnType<typeof setTimeout> | null = null;
|
||||||
let previous = 0;
|
let previous = 0;
|
||||||
// tslint:disable-next-line: only-arrow-functions
|
|
||||||
return function (arg: T) {
|
return function (arg: T) {
|
||||||
let now = Date.now();
|
const now = Date.now();
|
||||||
if (!previous && options.leading === false) {
|
if (!previous && options.leading === false) {
|
||||||
previous = now;
|
previous = now;
|
||||||
}
|
}
|
||||||
let remaining = wait - (now - previous);
|
const remaining = wait - (now - previous);
|
||||||
let context = this;
|
const context = this;
|
||||||
let args = arguments;
|
const args = arguments;
|
||||||
if (remaining <= 0 || remaining > wait) {
|
if (remaining <= 0 || remaining > wait) {
|
||||||
if (timeout) {
|
if (timeout) {
|
||||||
clearTimeout(timeout);
|
clearTimeout(timeout);
|
||||||
@@ -398,8 +397,7 @@ export function getNestedRule(
|
|||||||
return rule;
|
return rule;
|
||||||
} else {
|
} else {
|
||||||
return getNestedRule(
|
return getNestedRule(
|
||||||
((rule as CSSGroupingRule).cssRules[position[1]] as CSSGroupingRule)
|
(rule.cssRules[position[1]] as CSSGroupingRule).cssRules,
|
||||||
.cssRules,
|
|
||||||
position.slice(2),
|
position.slice(2),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,7 @@
|
|||||||
"exclude": ["test"],
|
"exclude": ["test"],
|
||||||
"include": [
|
"include": [
|
||||||
"src",
|
"src",
|
||||||
|
"scripts",
|
||||||
"node_modules/@types/css-font-loading-module/index.d.ts",
|
"node_modules/@types/css-font-loading-module/index.d.ts",
|
||||||
"node_modules/@types/jest-image-snapshot/index.d.ts"
|
"node_modules/@types/jest-image-snapshot/index.d.ts"
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,31 +0,0 @@
|
|||||||
{
|
|
||||||
"defaultSeverity": "error",
|
|
||||||
"extends": ["tslint:recommended"],
|
|
||||||
"jsRules": {},
|
|
||||||
"rules": {
|
|
||||||
"no-any": true,
|
|
||||||
"quotemark": [true, "single"],
|
|
||||||
"ordered-imports": false,
|
|
||||||
"object-literal-sort-keys": false,
|
|
||||||
"no-unused-variable": true,
|
|
||||||
"object-literal-key-quotes": false,
|
|
||||||
"variable-name": [
|
|
||||||
true,
|
|
||||||
"ban-keywords",
|
|
||||||
"check-format",
|
|
||||||
"allow-leading-underscore"
|
|
||||||
],
|
|
||||||
"arrow-parens": false,
|
|
||||||
"only-arrow-functions": false,
|
|
||||||
"max-line-length": false,
|
|
||||||
"no-empty": false,
|
|
||||||
"max-classes-per-file": false,
|
|
||||||
"semicolon": false,
|
|
||||||
"trailing-comma": false,
|
|
||||||
"curly": false,
|
|
||||||
"no-namespace": false,
|
|
||||||
"interface-name": false,
|
|
||||||
"forin": false
|
|
||||||
},
|
|
||||||
"rulesDirectory": []
|
|
||||||
}
|
|
||||||
4
tsconfig.eslint.json
Normal file
4
tsconfig.eslint.json
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"extends": "./tsconfig.json",
|
||||||
|
"include": [".eslintrc.js"]
|
||||||
|
}
|
||||||
1
tsconfig.json
Normal file
1
tsconfig.json
Normal file
@@ -0,0 +1 @@
|
|||||||
|
{}
|
||||||
Reference in New Issue
Block a user