1
0
mirror of https://github.com/laurent22/joplin.git synced 2026-02-22 08:47:34 +02:00

Compare commits

..

41 Commits

Author SHA1 Message Date
Laurent Cozic
60c755dbbf Merge branch 'dev' into check-pr-title 2023-11-24 16:57:13 +01:00
Laurent Cozic
84cc1576a8 CI: Add a comment when a pull request fails 2023-11-24 16:12:02 +01:00
Laurent Cozic
29b42b3b37 CI: Add a comment when a pull request fail 2023-11-24 16:10:23 +01:00
Laurent Cozic
3b15834e8d Tools: Check pull request titles 2023-11-24 14:56:05 +01:00
Laurent Cozic
d9ce98d374 pr only 2023-11-24 14:54:56 +01:00
Laurent Cozic
19531d229b check pr title 2023-11-24 14:53:31 +01:00
renovate[bot]
2b9bf6deba Update dependency @codemirror/autocomplete to v6.10.2 (#9352)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-24 14:47:21 +01:00
Joplin Bot
0abaeef05e Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-11-23 00:36:31 +00:00
renovate[bot]
b2e86d2f8a Update dependency @playwright/test to v1.39.0 (#9356)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-22 20:13:25 +01:00
Joplin Bot
52a3a59623 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-11-22 18:14:21 +00:00
renovate[bot]
c78afc46c9 Update dependency style-to-js to v1.1.9 (#9359)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-22 14:06:07 +00:00
renovate[bot]
9b89f4ecfb Update dependency @types/react to v18.2.34 (#9358)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-22 01:34:11 +00:00
renovate[bot]
99be29707f Update dependency @react-native-community/netinfo to v9.4.2 (#9357)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-21 18:29:01 +00:00
Henry Heino
2a62bbdbd3 Chore: Fixes #9353: CI: Run tests on pull requests from other branches of the main repository (#9354) 2023-11-21 16:10:37 +01:00
renovate[bot]
c5e15e93f4 Update dependency @types/node to v18.18.8 (#9351)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-20 14:11:58 +00:00
renovate[bot]
719e0e6104 Update dependency @types/node-fetch to v2.6.8 (#9349)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-20 01:51:54 +00:00
renovate[bot]
1eea2400cb Update dependency punycode to v2.3.1 (#9348)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-19 22:39:39 +00:00
renovate[bot]
83efd67ff8 Update dependency @testing-library/react-native to v12.3.2 (#9346)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-19 19:48:33 +00:00
renovate[bot]
8ef682dcf9 Update dependency rate-limiter-flexible to v3.0.3 (#9345)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-19 15:17:46 +00:00
Laurent Cozic
401d551daa Api: Search for partial matches by default, unless the query is surrounded by quotes 2023-11-19 11:44:34 +00:00
Laurent Cozic
8a533b2003 Desktop: Resolves #9343: Search for partial matches by default, unless the query is surrounded by quotes 2023-11-19 11:40:13 +00:00
Laurent Cozic
27f888d0c4 lock file 2023-11-19 11:22:36 +00:00
pedr
4aeb2fafb2 Clipper: add options to make fetchBlob exit faster, if needed (#9252)
Co-authored-by: Laurent Cozic <laurent22@users.noreply.github.com>
2023-11-19 10:44:27 +00:00
Henry Heino
dc20402f5b Chore: Mobile: Fix warning in image editor test (#9338) 2023-11-19 10:43:22 +00:00
renovate[bot]
9b078de9d8 Update dependency rate-limiter-flexible to v3 (#9339)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-19 10:42:19 +00:00
Laurent Cozic
214f9916d9 Server v2.13.5 2023-11-19 09:34:30 +00:00
Laurent Cozic
87aeffa160 Server: Fixed issue with sync not immediately returning all items in certain cases 2023-11-19 09:24:20 +00:00
Henry Heino
14a2d2d795 Chore: Mobile: Don't build twice on postinstall (#9340) 2023-11-19 08:55:52 +00:00
Joplin Bot
3560bc62a2 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-11-18 18:13:50 +00:00
Joplin Bot
0729d1db27 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-11-18 12:16:13 +00:00
renovate[bot]
5f27d425bf Update dependency highlight.js to v11.9.0 (#9341)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-18 10:53:36 +00:00
Joplin Bot
e2956c391d Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-11-18 06:14:34 +00:00
Joplin Bot
bdc8f30705 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-11-17 18:14:34 +00:00
Laurent Cozic
2c9bf9f03a Desktop: Fixed copying and pasting an image from Chrome in RTE 2023-11-17 18:11:17 +00:00
Henry Heino
60c2964acd Chore: Tests: Fix vscode doesn't recognize Jest types in some test files (#9337) 2023-11-17 16:04:36 +00:00
Joplin Bot
97248035b1 Doc: Auto-update documentation
Auto-updated using release-website.sh
2023-11-17 12:17:33 +00:00
Laurent Cozic
35c79a2cfb Doc: Fixes #9323: Fixed donation link 2023-11-17 12:01:45 +00:00
Henry Heino
9b9762f940 Chore: Mobile: Fix "MenuContext is deprecated" warning (#9330) 2023-11-17 11:43:01 +00:00
renovate[bot]
e186fe8936 Update dependency ts-loader to v9.5.0 (#9327)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-17 08:23:55 +00:00
renovate[bot]
213cd419f0 Update dependency node-gyp to v9.4.1 (#9333)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-17 02:20:51 +00:00
renovate[bot]
b89b5fef65 Update dependency ldapts to v7.0.6 (#9332)
Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
2023-11-16 22:06:40 +00:00
73 changed files with 785 additions and 703 deletions

View File

@@ -249,6 +249,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.test.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
@@ -542,7 +544,6 @@ packages/editor/CodeMirror/editorCommands/swapLine.js
packages/editor/CodeMirror/getScrollFraction.js
packages/editor/CodeMirror/markdown/computeSelectionFormatting.test.js
packages/editor/CodeMirror/markdown/computeSelectionFormatting.js
packages/editor/CodeMirror/markdown/decoratorExtension.test.js
packages/editor/CodeMirror/markdown/decoratorExtension.js
packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.js
packages/editor/CodeMirror/markdown/markdownCommands.test.js

View File

@@ -8,16 +8,23 @@ SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" &> /dev/null && pwd )"
ROOT_DIR="$SCRIPT_DIR/../.."
IS_PULL_REQUEST=0
IS_DEV_BRANCH=0
IS_DESKTOP_RELEASE=0
IS_SERVER_RELEASE=0
IS_LINUX=0
IS_MACOS=0
# If pull requests are coming from a branch of the main repository,
# IS_PULL_REQUEST will be zero.
if [ "$GITHUB_EVENT_NAME" == "pull_request" ]; then
IS_PULL_REQUEST=1
fi
if [ "$GITHUB_REF" == "refs/heads/dev" ]; then
IS_DEV_BRANCH=1
if [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
IS_SERVER_RELEASE=1
fi
if [[ $GIT_TAG_NAME = v* ]]; then
IS_DESKTOP_RELEASE=1
fi
if [ "$RUNNER_OS" == "Linux" ]; then
@@ -28,6 +35,14 @@ else
IS_MACOS=1
fi
# Tests can randomly fail in some cases, so only run them when not publishing
# a release
RUN_TESTS=0
if [ "$IS_SERVER_RELEASE" = 0 ] && [ "$IS_DESKTOP_RELEASE" = 0 ]; then
RUN_TESTS=1
fi
# =============================================================================
# Print environment
# =============================================================================
@@ -43,7 +58,9 @@ echo "SERVER_TAG_PREFIX=$SERVER_TAG_PREFIX"
echo "IS_CONTINUOUS_INTEGRATION=$IS_CONTINUOUS_INTEGRATION"
echo "IS_PULL_REQUEST=$IS_PULL_REQUEST"
echo "IS_DEV_BRANCH=$IS_DEV_BRANCH"
echo "IS_DESKTOP_RELEASE=$IS_DESKTOP_RELEASE"
echo "IS_SERVER_RELEASE=$IS_SERVER_RELEASE"
echo "RUN_TESTS=$RUN_TESTS"
echo "IS_LINUX=$IS_LINUX"
echo "IS_MACOS=$IS_MACOS"
@@ -64,11 +81,10 @@ if [ $testResult -ne 0 ]; then
fi
# =============================================================================
# Run test units. Only do it for pull requests and dev branch because we don't
# want it to randomly fail when trying to create a desktop release.
# Run test units
# =============================================================================
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
if [ "$RUN_TESTS" == "1" ]; then
echo "Step: Running tests..."
# On Linux, we run the Joplin Server tests using PostgreSQL
@@ -102,7 +118,7 @@ fi
# Check that the website builder can run without errors
# =============================================================================
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
if [ "$RUN_TESTS" == "1" ]; then
if [ "$IS_LINUX" == "1" ]; then
echo "Step: Running website builder..."
node packages/tools/website/processDocs.js --env dev
@@ -114,7 +130,7 @@ fi
# release randomly fail.
# =============================================================================
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
if [ "$RUN_TESTS" == "1" ]; then
echo "Step: Running linter..."
yarn run linter-ci ./
@@ -154,7 +170,7 @@ fi
# what commit may have broken translation building.
# =============================================================================
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
if [ "$RUN_TESTS" == "1" ]; then
if [ "$IS_LINUX" == "1" ]; then
echo "Step: Checking for lost translation strings..."
@@ -190,7 +206,7 @@ fi
# Check that the website still builds
# =============================================================================
if [ "$IS_PULL_REQUEST" == "1" ] || [ "$IS_DEV_BRANCH" = "1" ]; then
if [ "$RUN_TESTS" == "1" ]; then
echo "Step: Check that the website still builds..."
mkdir -p ../joplin-website/docs
@@ -226,7 +242,7 @@ fi
cd "$ROOT_DIR/packages/app-desktop"
if [[ $GIT_TAG_NAME = v* ]]; then
if [ "$IS_DESKTOP_RELEASE" == "1" ]; then
echo "Step: Building and publishing desktop application..."
# cd "$ROOT_DIR/packages/tools"
# node bundleDefaultPlugins.js
@@ -251,7 +267,7 @@ if [[ $GIT_TAG_NAME = v* ]]; then
else
USE_HARD_LINKS=false yarn run dist
fi
elif [[ $IS_LINUX = 1 ]] && [[ $GIT_TAG_NAME = $SERVER_TAG_PREFIX-* ]]; then
elif [[ $IS_LINUX = 1 ]] && [ "$IS_SERVER_RELEASE" == "1" ]; then
echo "Step: Building Docker Image..."
cd "$ROOT_DIR"
yarn run buildServerDocker --tag-name $GIT_TAG_NAME --push-images --repository $SERVER_REPOSITORY

8
.github/workflows/check-pr-title.yml vendored Normal file
View File

@@ -0,0 +1,8 @@
name: Check pull request title
on: [pull_request]
jobs:
main:
steps:
- uses: Slashgear/action-check-pr-title@v4.3.0
with:
regexp: "(Desktop|Mobile|All|Cli|Tools|Chore|Clipper|Server|Android|iOS|Plugins): (Fixes|Resolves) #[0-9]+: .+"

View File

@@ -0,0 +1,14 @@
name: comment-on-failure
on:
workflow_run:
workflows:
- Joplin Continuous Integration
- react-native-android-build-apk
- Build macOS M1
types: [ completed ]
jobs:
comment-failure:
runs-on: ubuntu-latest
steps:
- uses: quipper/comment-failure-action@v0.1.1

3
.gitignore vendored
View File

@@ -231,6 +231,8 @@ packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/styles/index.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/joplinCommandToTinyMceCommands.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/openEditDialog.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/setupToolbarButtons.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.test.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/shouldPasteResources.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/types.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useContextMenu.js
packages/app-desktop/gui/NoteEditor/NoteBody/TinyMCE/utils/useScroll.js
@@ -524,7 +526,6 @@ packages/editor/CodeMirror/editorCommands/swapLine.js
packages/editor/CodeMirror/getScrollFraction.js
packages/editor/CodeMirror/markdown/computeSelectionFormatting.test.js
packages/editor/CodeMirror/markdown/computeSelectionFormatting.js
packages/editor/CodeMirror/markdown/decoratorExtension.test.js
packages/editor/CodeMirror/markdown/decoratorExtension.js
packages/editor/CodeMirror/markdown/markdownCommands.bulletedVsChecklist.test.js
packages/editor/CodeMirror/markdown/markdownCommands.test.js

View File

@@ -26,7 +26,7 @@ For more information about the applications, see the [full Joplin documentation]
Donations to Joplin support the development of the project. Developing quality applications mostly takes time, but there are also some expenses, such as digital certificates to sign the applications, app store fees, hosting, etc. Most of all, your donation will make it possible to keep up the current development standard.
Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/readme/about/donate.md) for information on how to support the development of Joplin.
Please see the [donation page](https://github.com/laurent22/joplin/blob/dev/readme/donate.md) for information on how to support the development of Joplin.
# Sponsors

View File

@@ -96,7 +96,7 @@
"@types/fs-extra": "11.0.3",
"eslint-plugin-github": "4.10.0",
"http-server": "14.1.1",
"node-gyp": "9.4.0",
"node-gyp": "9.4.1",
"nodemon": "3.0.1"
},
"packageManager": "yarn@3.6.4",

View File

@@ -35,7 +35,7 @@
],
"owner": "Laurent Cozic"
},
"version": "2.13.2",
"version": "2.13.1",
"bin": "./main.js",
"engines": {
"node": ">=10.0.0"
@@ -73,7 +73,7 @@
"@joplin/tools": "~2.13",
"@types/fs-extra": "11.0.3",
"@types/jest": "29.5.5",
"@types/node": "18.18.7",
"@types/node": "18.18.8",
"@types/proper-lockfile": "^4.1.2",
"gulp": "4.0.2",
"jest": "29.7.0",

View File

@@ -291,29 +291,4 @@ describe('MdToHtml', () => {
expect(html.html).toContain(opening + trimmedTex + closing);
}
});
it('should render inline KaTeX after a numbered equation', async () => {
const mdToHtml = newTestMdToHtml();
// This test is intended to verify that inline KaTeX renders correctly
// after creating a numbered equation with \begin{align}...\end{align}.
//
// See https://github.com/laurent22/joplin/issues/9455 for details.
const markdown = [
'$$',
'\\begin{align}\\text{Block}\\end{align}',
'$$',
'',
'$\\text{Inline}$',
].join('\n');
const { html } = await mdToHtml.render(markdown, null, { bodyOnly: true });
// Because we don't control the output of KaTeX, this test should be as general as
// possible while still verifying that rendering (without an error) occurs.
// Should have rendered the inline and block content without errors
expect(html).toContain('Inline</span>');
expect(html).toContain('Block</span>');
});
});

View File

@@ -7,7 +7,7 @@
<en-note><div>Plain note</div></en-note>]]></content><created>20201223T163948Z</created><updated>20201223T163953Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>Note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 130px;"/><col style="width: 130px;"/><col style="width: 130px;"/></colgroup><tbody><tr<td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div><br/></div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bl</div></t><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td></tr></tbody></table><div><br/></div></div><div><br/></div></en-note>]]></content><created>20201223T164010Z</created><updated>20201223T164023Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>plain note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<en-note><div><div><br/></div><table style="border-collapse: collapse; min-width: 100%;"><colgroup><col style="width: 130px;"/><col style="width: 130px;"/><col style="width: 130px;"/></colgroup><tbody><tr<td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>test</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div><br/></div></td></tr><tr><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bl</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td><td style="width: 130px; padding: 8px; border: 1px solid;"><div>bla</div></td></tr></tbody></table><div><br/></div></div><div><br/></div></en-note>]]></content><created>20201223T164010Z</created><updated>20201223T164023Z</updated><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note><note><title>plain note 2</title><content><![CDATA[<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE en-note SYSTEM "http://xml.evernote.com/pub/enml2.dtd">
<en-note><div><br/></div></en-note>]]></content><created>20201223T164236Z</created><note-attributes><author>laurent22777@gmail.com</author><source>desktop.win</source><source-application>evernote.win32</source-application></note-attributes></note></en-export>

File diff suppressed because one or more lines are too long

View File

@@ -1,12 +0,0 @@
<table>
<div></div> <!-- INVALID! -->
<tr>
<td>one</td>
<td>two</td>
</tr>
<tr>
<div></div> <!-- INVALID! -->
<td>three</td>
<td>four</td>
</tr>
</table>

View File

@@ -1,4 +0,0 @@
| | |
| --- | --- |
| one | two |
| three | four |

View File

@@ -1,10 +1,10 @@
<body>
<table>
<table border="5px" bordercolor="#8707B0">
<tr>
<td>Left side of the main table</td>
<td>
<table>
<b>Nested Table</b>
<table border="5px" bordercolor="#F35557">
<h4 align="center">Nested Table</h4>
<tr>
<td>nested table C1</td>
<td>nested table C2</td>

View File

@@ -1 +1 @@
<table><tbody><tr><td>Left side of the main table</td><td><b>Nested Table</b><table><tbody><tr><td>nested table C1</td><td>nested table C2</td></tr><tr><td>nested table</td><td>nested table</td></tr></tbody></table></td></tr></tbody></table>
<table border="5px" bordercolor="#8707B0"><tbody><tr><td>Left side of the main table</td><td><h4 align="center">Nested Table</h4><table border="5px" bordercolor="#F35557"><tbody><tr><td>nested table C1</td><td>nested table C2</td></tr><tr><td>nested table</td><td>nested table</td></tr></tbody></table></td></tr></tbody></table>

View File

@@ -27,6 +27,7 @@ import bridge from '../../../../services/bridge';
import { TinyMceEditorEvents } from './utils/types';
import type { Editor } from 'tinymce';
import { joplinCommandToTinyMceCommands, TinyMceCommand } from './utils/joplinCommandToTinyMceCommands';
import shouldPasteResources from './utils/shouldPasteResources';
const { clipboard } = require('electron');
const supportedLocales = require('./supportedLocales');
@@ -1085,15 +1086,9 @@ const TinyMCE = (props: NoteBodyEditorProps, ref: any) => {
// formatted text.
const pastedHtml = event.clipboardData.getData('text/html') ? clipboard.readHTML() : '';
// We should only process the images if there is no plain text or
// HTML text in the clipboard. This is because certain applications,
// such as Word, are going to add multiple versions of the copied
// data to the clipboard - one with the text formatted as HTML, and
// one with the text as an image. In that case, we need to ignore
// the image and only process the HTML.
const resourceMds = await getResourcesFromPasteEvent(event);
if (!pastedText && !pastedHtml) {
const resourceMds = await getResourcesFromPasteEvent(event);
if (shouldPasteResources(pastedText, pastedHtml, resourceMds)) {
if (resourceMds.length) {
const result = await markupToHtml.current(MarkupToHtml.MARKUP_LANGUAGE_MARKDOWN, resourceMds.join('\n'), markupRenderOptions({ bodyOnly: true }));
editor.insertContent(result.html);

View File

@@ -0,0 +1,47 @@
import shouldPasteResources from './shouldPasteResources';
describe('shouldPasteResources', () => {
test.each([
[
'',
'',
[],
true,
],
[
'some text',
'',
[],
false,
],
[
'',
'<b>some html<b>',
[],
false,
],
[
'',
'<img src="https://example.com/img.png"/>',
[],
false,
],
[
'some text',
'<img src="https://example.com/img.png"/>',
[],
false,
],
[
'',
'<img src="https://example.com/img.png"/><p>Some text</p>',
[],
false,
],
])('should tell if clipboard content should be processed as resources', (pastedText, pastedHtml, resourceMds, expected) => {
const actual = shouldPasteResources(pastedText, pastedHtml, resourceMds);
expect(actual).toBe(expected);
});
});

View File

@@ -0,0 +1,49 @@
import { htmlDocIsImageOnly } from '@joplin/renderer/htmlUtils';
import Logger from '@joplin/utils/Logger';
const logger = Logger.create('shouldPasteResources');
// We should only process the images if there is no plain text or HTML text in
// the clipboard. This is because certain applications, such as Word, are going
// to add multiple versions of the copied data to the clipboard - one with the
// text formatted as HTML, and one with the text as an image. In that case, we
// need to ignore the image and only process the HTML.
//
// Additional source of troubles is that when copying an image from Chrome, the
// clipboard will contain two elements: The actual image (type=image), and an
// HTML fragment with a link to the image. Most of the time getting the image
// from the HTML will work... except if some authentication is required to
// access the image. In that case we'll end up with dead link in the RTE. For
// that reason, when there's only an image in the HTML document, we process
// instead the clipboard resources, which will contain the actual image.
//
// We have a lot of log statements so that if someone reports a bug we can ask
// them to check the console and give us the messages they have.
export default (pastedText: string, pastedHtml: string, resourceMds: string[]) => {
logger.info('Pasted text:', pastedText);
logger.info('Pasted HTML:', pastedHtml);
logger.info('Resources:', resourceMds);
if (pastedText) {
logger.info('Not pasting resources because the clipboard contains plain text');
return false;
}
if (pastedHtml) {
if (!htmlDocIsImageOnly(pastedHtml)) {
logger.info('Not pasting resources because the clipboard contains HTML, which contains more than just one image');
return false;
} else {
logger.info('Not pasting HTML because it only contains one image.');
}
if (!resourceMds.length) {
logger.info('Not pasting resources because there isn\'t any');
return false;
}
}
logger.info('Pasting resources');
return true;
};

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/app-desktop",
"version": "2.13.12",
"version": "2.13.6",
"description": "Joplin for Desktop",
"main": "main.js",
"private": true,
@@ -117,11 +117,11 @@
"devDependencies": {
"@electron/rebuild": "3.3.0",
"@joplin/tools": "~2.13",
"@playwright/test": "1.38.1",
"@playwright/test": "1.39.0",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.5.5",
"@types/node": "18.18.7",
"@types/react": "18.2.33",
"@types/node": "18.18.8",
"@types/react": "18.2.34",
"@types/react-redux": "7.1.28",
"@types/styled-components": "5.1.29",
"electron": "26.5.0",
@@ -159,7 +159,7 @@
"electron-window-state": "5.0.3",
"formatcoords": "1.1.3",
"fs-extra": "11.1.1",
"highlight.js": "11.8.0",
"highlight.js": "11.9.0",
"immer": "7.0.15",
"keytar": "7.9.0",
"mark.js": "8.11.1",

View File

@@ -110,8 +110,8 @@ android {
applicationId "net.cozic.joplin"
minSdkVersion rootProject.ext.minSdkVersion
targetSdkVersion rootProject.ext.targetSdkVersion
versionCode 2097730
versionName "2.13.10"
versionCode 2097727
versionName "2.13.7"
ndk {
abiFilters "armeabi-v7a", "x86", "arm64-v8a", "x86_64"
}

View File

@@ -1,12 +1,10 @@
const React = require('react');
import { useState, useCallback, useMemo } from 'react';
const Icon = require('react-native-vector-icons/Ionicons').default;
import { FAB, Portal } from 'react-native-paper';
import { _ } from '@joplin/lib/locale';
import { Dispatch } from 'redux';
const Icon = require('react-native-vector-icons/Ionicons').default;
// eslint-disable-next-line no-undef -- Don't know why it says React is undefined when it's defined above
type FABGroupProps = React.ComponentProps<typeof FAB.Group>;
type OnButtonPress = ()=> void;
interface ButtonSpec {
@@ -21,7 +19,6 @@ interface ActionButtonProps {
// If not given, an "add" button will be used.
mainButton?: ButtonSpec;
dispatch: Dispatch;
}
const defaultOnPress = () => {};
@@ -39,12 +36,10 @@ const useIcon = (iconName: string) => {
const ActionButton = (props: ActionButtonProps) => {
const [open, setOpen] = useState(false);
const onMenuToggled: FABGroupProps['onStateChange'] = useCallback(state => {
props.dispatch({
type: 'SIDE_MENU_CLOSE',
});
setOpen(state.open);
}, [setOpen, props.dispatch]);
const onMenuToggled = useCallback(
(state: { open: boolean }) => setOpen(state.open)
, [setOpen]);
const actions = useMemo(() => (props.buttons ?? []).map(button => {
return {

View File

@@ -124,6 +124,7 @@ export const createJsDrawEditor = (
return new Promise<string>((resolve, reject) => {
if (!resourceUrl) {
resolve('');
return;
}
// fetch seems to be unable to request file:// URLs.
@@ -156,6 +157,10 @@ export const createJsDrawEditor = (
// Load from a template if no initial data
if (svgData === '') {
await applyTemplateToEditor(editor, templateData);
// The editor expects to be saved initially (without
// unsaved changes). Save now.
saveNow();
} else {
await editor.loadFromSVG(svgData);
}

View File

@@ -270,7 +270,6 @@ function NoteEditor(props: Props, ref: any) {
const setInitialSelectionJS = props.initialSelection ? `
cm.select(${props.initialSelection.start}, ${props.initialSelection.end});
cm.execCommand('scrollSelectionIntoView');
` : '';
const editorSettings: EditorSettings = {
@@ -332,7 +331,6 @@ function NoteEditor(props: Props, ref: any) {
const settings = ${JSON.stringify(editorSettings)};
cm = codeMirrorBundle.initCodeMirror(parentElement, initialText, settings);
${setInitialSelectionJS}
window.onresize = () => {

View File

@@ -40,7 +40,9 @@ interface ActionButtonProps {
onPress: Callback;
}
const ActionButton = (props: ActionButtonProps) => {
const ActionButton = (
props: ActionButtonProps,
) => {
return (
<CustomButton
themeId={props.themeId}

View File

@@ -10,7 +10,6 @@ import NoteEditor from '../NoteEditor/NoteEditor';
const FileViewer = require('react-native-file-viewer').default;
const React = require('react');
const { Keyboard, View, TextInput, StyleSheet, Linking, Image, Share } = require('react-native');
import type { NativeSyntheticEvent } from 'react-native';
import { Platform, PermissionsAndroid } from 'react-native';
const { connect } = require('react-redux');
// const { MarkdownEditor } = require('@joplin/lib/../MarkdownEditor/index.js');
@@ -51,9 +50,8 @@ import isEditableResource from '../NoteEditor/ImageEditor/isEditableResource';
import VoiceTypingDialog from '../voiceTyping/VoiceTypingDialog';
import { voskEnabled } from '../../services/voiceTyping/vosk';
import { isSupportedLanguage } from '../../services/voiceTyping/vosk.android';
import { ChangeEvent as EditorChangeEvent, SelectionRangeChangeEvent, UndoRedoDepthChangeEvent } from '@joplin/editor/events';
import { ChangeEvent as EditorChangeEvent, UndoRedoDepthChangeEvent } from '@joplin/editor/events';
import { join } from 'path';
import { SelectionRange } from '../NoteEditor/types';
const urlUtils = require('@joplin/lib/urlUtils');
// import Vosk from 'react-native-vosk';
@@ -66,7 +64,6 @@ class NoteScreenComponent extends BaseScreenComponent {
// This isn't in this.state because we don't want changing scroll to trigger
// a re-render.
private lastBodyScroll: number|undefined = undefined;
private selection: SelectionRange;
public static navigationOptions(): any {
return { header: null };
@@ -254,6 +251,7 @@ class NoteScreenComponent extends BaseScreenComponent {
this.undoRedoService_stackChange = this.undoRedoService_stackChange.bind(this);
this.screenHeader_undoButtonPress = this.screenHeader_undoButtonPress.bind(this);
this.screenHeader_redoButtonPress = this.screenHeader_redoButtonPress.bind(this);
this.body_selectionChange = this.body_selectionChange.bind(this);
this.onBodyViewerLoadEnd = this.onBodyViewerLoadEnd.bind(this);
this.onBodyViewerCheckboxChange = this.onBodyViewerCheckboxChange.bind(this);
this.onBodyChange = this.onBodyChange.bind(this);
@@ -522,13 +520,13 @@ class NoteScreenComponent extends BaseScreenComponent {
this.scheduleSave();
}
private onPlainEdtiorSelectionChange = (event: NativeSyntheticEvent<any>) => {
this.selection = event.nativeEvent.selection;
};
private onMarkdownEditorSelectionChange = (event: SelectionRangeChangeEvent) => {
this.selection = { start: event.from, end: event.to };
};
private body_selectionChange(event: any) {
if (this.useEditorBeta()) {
this.selection = event.selection;
} else {
this.selection = event.nativeEvent.selection;
}
}
public makeSaveAction() {
return async () => {
@@ -751,11 +749,7 @@ class NoteScreenComponent extends BaseScreenComponent {
if (this.useEditorBeta()) {
// The beta editor needs to be explicitly informed of changes
// to the note's body
if (this.editorRef.current) {
this.editorRef.current.insertText(newText);
} else {
logger.error(`Tried to attach resource ${resource.id} to the note when the editor is not visible!`);
}
this.editorRef.current.insertText(newText);
}
} else {
newNote.body += `\n${resourceTag}`;
@@ -820,34 +814,31 @@ class NoteScreenComponent extends BaseScreenComponent {
}, 'image');
}
private drawPicture_onPress = async () => {
// Create a new empty drawing and attach it now.
const resource = await this.attachNewDrawing('');
await this.editDrawing(resource);
};
private async updateDrawing(svgData: string) {
let resource: ResourceEntity|null = this.state.imageEditorResource;
if (!resource) {
resource = await this.attachNewDrawing(svgData);
// Set resouce and file path to allow
// 1. subsequent saves to update the resource
// 2. the editor to load from the resource's filepath (can happen
// if the webview is reloaded).
this.setState({
imageEditorResourceFilepath: Resource.fullPath(resource),
imageEditorResource: resource,
});
} else {
logger.info('Saving drawing to resource', resource.id);
const tempFilePath = join(Setting.value('tempDir'), uuid.createNano());
await shim.fsDriver().writeFile(tempFilePath, svgData, 'utf8');
resource = await Resource.updateResourceBlobContent(
resource.id,
tempFilePath,
);
await shim.fsDriver().remove(tempFilePath);
await this.refreshResource(resource);
throw new Error('No resource is loaded in the editor');
}
logger.info('Saving drawing to resource', resource.id);
const tempFilePath = join(Setting.value('tempDir'), uuid.createNano());
await shim.fsDriver().writeFile(tempFilePath, svgData, 'utf8');
resource = await Resource.updateResourceBlobContent(
resource.id,
tempFilePath,
);
await shim.fsDriver().remove(tempFilePath);
await this.refreshResource(resource);
}
private onSaveDrawing = async (svgData: string) => {
@@ -858,23 +849,6 @@ class NoteScreenComponent extends BaseScreenComponent {
this.setState({ showImageEditor: false });
};
private drawPicture_onPress = async () => {
if (this.state.mode === 'edit') {
// Create a new empty drawing and attach it now, before the image editor is opened.
// With the present structure of Note.tsx, the we can't use this.editorRef while
// the image editor is open, and thus can't attach drawings at the cursor locaiton.
const resource = await this.attachNewDrawing('');
await this.editDrawing(resource);
} else {
logger.info('Showing image editor...');
this.setState({
showImageEditor: true,
imageEditorResourceFilepath: null,
imageEditorResource: null,
});
}
};
private async editDrawing(item: BaseItem) {
const filePath = Resource.fullPath(item);
this.setState({
@@ -1394,7 +1368,7 @@ class NoteScreenComponent extends BaseScreenComponent {
multiline={true}
value={note.body}
onChangeText={(text: string) => this.body_changeText(text)}
onSelectionChange={this.onPlainEdtiorSelectionChange}
onSelectionChange={this.body_selectionChange}
blurOnSubmit={false}
selectionColor={theme.textSelectionColor}
keyboardAppearance={theme.keyboardAppearance}
@@ -1415,7 +1389,7 @@ class NoteScreenComponent extends BaseScreenComponent {
initialText={note.body}
initialSelection={this.selection}
onChange={this.onBodyChange}
onSelectionChange={this.onMarkdownEditorSelectionChange}
onSelectionChange={this.body_selectionChange}
onUndoRedoDepthChange={this.onUndoRedoDepthChange}
onAttach={() => this.showAttachMenu()}
readOnly={this.state.readOnly}
@@ -1448,7 +1422,7 @@ class NoteScreenComponent extends BaseScreenComponent {
if (this.state.mode === 'edit') return null;
return <ActionButton mainButton={editButton} dispatch={this.props.dispatch} />;
return <ActionButton mainButton={editButton} />;
};
// Save button is not really needed anymore with the improved save logic

View File

@@ -16,7 +16,6 @@ const DialogBox = require('react-native-dialogbox').default;
const { BaseScreenComponent } = require('../base-screen');
const { BackButtonService } = require('../../services/back-button.js');
import { AppState } from '../../utils/types';
const { ALL_NOTES_FILTER_ID } = require('@joplin/lib/reserved-ids.js');
class NotesScreenComponent extends BaseScreenComponent<any> {
@@ -109,7 +108,7 @@ class NotesScreenComponent extends BaseScreenComponent<any> {
}
public async componentDidUpdate(prevProps: any) {
if (prevProps.notesOrder !== this.props.notesOrder || prevProps.selectedFolderId !== this.props.selectedFolderId || prevProps.selectedTagId !== this.props.selectedTagId || prevProps.selectedSmartFilterId !== this.props.selectedSmartFilterId || prevProps.notesParentType !== this.props.notesParentType || prevProps.uncompletedTodosOnTop !== this.props.uncompletedTodosOnTop || prevProps.showCompletedTodos !== this.props.showCompletedTodos) {
if (prevProps.notesOrder !== this.props.notesOrder || prevProps.selectedFolderId !== this.props.selectedFolderId || prevProps.selectedTagId !== this.props.selectedTagId || prevProps.selectedSmartFilterId !== this.props.selectedSmartFilterId || prevProps.notesParentType !== this.props.notesParentType) {
await this.refreshNotes(this.props);
}
}
@@ -224,32 +223,17 @@ class NotesScreenComponent extends BaseScreenComponent<any> {
let buttonFolderId = this.props.selectedFolderId !== Folder.conflictFolderId() ? this.props.selectedFolderId : null;
if (!buttonFolderId) buttonFolderId = this.props.activeFolderId;
const isAllNotes =
this.props.notesParentType === 'SmartFilter'
&& this.props.selectedSmartFilterId === ALL_NOTES_FILTER_ID;
// Usually, when showing all notes, activeFolderId/selectedFolderId is set to the last
// active folder.
// If the app starts showing all notes, activeFolderId/selectedFolderId are
// empty or null. As such, we need a special case to show the buttons:
const addFolderNoteButtons = !!buttonFolderId || isAllNotes;
const addFolderNoteButtons = !!buttonFolderId;
const thisComp = this;
const makeActionButtonComp = () => {
const getTargetFolderId = async () => {
if (!buttonFolderId && isAllNotes) {
return (await Folder.defaultFolder()).id;
}
return buttonFolderId;
};
if (addFolderNoteButtons && this.props.folders.length > 0) {
const buttons = [];
buttons.push({
label: _('New to-do'),
onPress: async () => {
const folderId = await getTargetFolderId();
onPress: () => {
const isTodo = true;
void this.newNoteNavigate(folderId, isTodo);
void this.newNoteNavigate(buttonFolderId, isTodo);
},
color: '#9b59b6',
icon: 'checkbox-outline',
@@ -257,15 +241,14 @@ class NotesScreenComponent extends BaseScreenComponent<any> {
buttons.push({
label: _('New note'),
onPress: async () => {
const folderId = await getTargetFolderId();
onPress: () => {
const isTodo = false;
void this.newNoteNavigate(folderId, isTodo);
void this.newNoteNavigate(buttonFolderId, isTodo);
},
color: '#9b59b6',
icon: 'document',
});
return <ActionButton buttons={buttons} dispatch={this.props.dispatch}/>;
return <ActionButton buttons={buttons}/>;
}
return null;
};

View File

@@ -45,9 +45,6 @@ LogBox.ignoreLogs([
// Apparently it can be safely ignored:
// https://github.com/react-native-webview/react-native-webview/issues/124
'Did not receive response to shouldStartLoad in time, defaulting to YES',
// Emitted by react-native-popup-menu
'MenuContext is deprecated and it might be removed in future releases, use MenuProvider instead.',
]);
AppRegistry.registerComponent('Joplin', () => Root);

View File

@@ -523,13 +523,13 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
CURRENT_PROJECT_VERSION = 107;
CURRENT_PROJECT_VERSION = 104;
DEVELOPMENT_TEAM = A9BXAFS6CT;
ENABLE_BITCODE = NO;
INFOPLIST_FILE = Joplin/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 12.13.10;
MARKETING_VERSION = 12.13.7;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -552,12 +552,12 @@
ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
CLANG_ENABLE_MODULES = YES;
CODE_SIGN_ENTITLEMENTS = Joplin/Joplin.entitlements;
CURRENT_PROJECT_VERSION = 107;
CURRENT_PROJECT_VERSION = 104;
DEVELOPMENT_TEAM = A9BXAFS6CT;
INFOPLIST_FILE = Joplin/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
MARKETING_VERSION = 12.13.10;
MARKETING_VERSION = 12.13.7;
OTHER_LDFLAGS = (
"$(inherited)",
"-ObjC",
@@ -704,14 +704,14 @@
CLANG_WARN_UNGUARDED_AVAILABILITY = YES_AGGRESSIVE;
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
CURRENT_PROJECT_VERSION = 107;
CURRENT_PROJECT_VERSION = 104;
DEBUG_INFORMATION_FORMAT = dwarf;
DEVELOPMENT_TEAM = A9BXAFS6CT;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ShareExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 12.13.10;
MARKETING_VERSION = 12.13.7;
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
@@ -735,14 +735,14 @@
CODE_SIGN_ENTITLEMENTS = ShareExtension/ShareExtension.entitlements;
CODE_SIGN_STYLE = Automatic;
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 107;
CURRENT_PROJECT_VERSION = 104;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
DEVELOPMENT_TEAM = A9BXAFS6CT;
GCC_C_LANGUAGE_STANDARD = gnu11;
INFOPLIST_FILE = ShareExtension/Info.plist;
IPHONEOS_DEPLOYMENT_TARGET = 11.0;
LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @executable_path/../../Frameworks";
MARKETING_VERSION = 12.13.10;
MARKETING_VERSION = 12.13.7;
MTL_FAST_MATH = YES;
PRODUCT_BUNDLE_IDENTIFIER = net.cozic.joplin.ShareExtension;
PRODUCT_NAME = "$(TARGET_NAME)";

View File

@@ -15,7 +15,7 @@
"test": "jest",
"test-ci": "yarn test",
"watchInjectedJs": "gulp watchInjectedJs",
"postinstall": "jetify && yarn run build"
"postinstall": "jetify"
},
"dependencies": {
"@bam.tech/react-native-image-resizer": "3.0.7",
@@ -28,7 +28,7 @@
"@react-native-community/clipboard": "1.5.1",
"@react-native-community/datetimepicker": "7.6.1",
"@react-native-community/geolocation": "3.1.0",
"@react-native-community/netinfo": "9.4.1",
"@react-native-community/netinfo": "9.4.2",
"@react-native-community/push-notification-ios": "1.11.0",
"@react-native-community/slider": "4.4.3",
"assert-browserify": "2.0.0",
@@ -42,7 +42,7 @@
"md5": "2.3.0",
"path-browserify": "1.0.1",
"prop-types": "15.8.1",
"punycode": "2.3.0",
"punycode": "2.3.1",
"react": "18.2.0",
"react-native": "0.71.10",
"react-native-camera": "4.2.1",
@@ -88,14 +88,14 @@
"@babel/preset-env": "7.20.2",
"@babel/runtime": "7.20.0",
"@joplin/tools": "~2.13",
"@js-draw/material-icons": "1.14.0",
"@js-draw/material-icons": "1.11.2",
"@lezer/highlight": "1.1.4",
"@testing-library/jest-native": "5.4.3",
"@testing-library/react-native": "12.3.1",
"@testing-library/react-native": "12.3.2",
"@tsconfig/react-native": "2.0.2",
"@types/fs-extra": "11.0.3",
"@types/jest": "29.5.5",
"@types/react": "18.2.33",
"@types/react": "18.2.34",
"@types/react-native": "0.70.6",
"@types/react-redux": "7.1.28",
"@types/tar-stream": "2.2.3",
@@ -106,14 +106,14 @@
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"jetifier": "2.0.0",
"js-draw": "1.14.0",
"js-draw": "1.11.2",
"jsdom": "22.1.0",
"metro-react-native-babel-preset": "0.73.9",
"nodemon": "3.0.1",
"react-test-renderer": "18.2.0",
"sqlite3": "5.1.6",
"ts-jest": "29.1.1",
"ts-loader": "9.4.4",
"ts-loader": "9.5.0",
"ts-node": "10.9.1",
"typescript": "5.2.2",
"uglify-js": "3.17.4",

View File

@@ -66,7 +66,7 @@ const { SearchScreen } = require('./components/screens/search.js');
const { OneDriveLoginScreen } = require('./components/screens/onedrive-login.js');
import EncryptionConfigScreen from './components/screens/encryption-config';
const { DropboxLoginScreen } = require('./components/screens/dropbox-login.js');
const { MenuContext } = require('react-native-popup-menu');
import { MenuProvider } from 'react-native-popup-menu';
import SideMenu from './components/SideMenu';
import SideMenuContent from './components/side-menu-content';
const { SideMenuContentNote } = require('./components/side-menu-content-note.js');
@@ -317,7 +317,6 @@ const appReducer = (state = appDefaultState, action: any) => {
if ('smartFilterId' in action) {
newState.smartFilterId = action.smartFilterId;
newState.selectedSmartFilterId = action.smartFilterId;
newState.notesParentType = 'SmartFilter';
}
@@ -1089,7 +1088,7 @@ class AppComponent extends React.Component {
}}
>
<StatusBar barStyle={statusBarStyle} />
<MenuContext style={{ flex: 1 }}>
<MenuProvider style={{ flex: 1 }}>
<SafeAreaView style={{ flex: 0, backgroundColor: theme.backgroundColor2 }}/>
<SafeAreaView style={{ flex: 1 }}>
<View style={{ flex: 1, backgroundColor: theme.backgroundColor }}>
@@ -1102,7 +1101,7 @@ class AppComponent extends React.Component {
sensorInfo={this.state.sensorInfo}
/> }
</SafeAreaView>
</MenuContext>
</MenuProvider>
</SideMenu>
</View>
);

View File

@@ -7,8 +7,6 @@
"exclude": [
//Files that don't need transpilation
"**/node_modules",
"**/*.test.ts",
"**/*.test.tsx",
"gulpfile.ts",
"tools/*.ts",
],

View File

@@ -1,30 +0,0 @@
import { EditorSelection } from '@codemirror/state';
import createTestEditor from '../testUtil/createTestEditor';
import decoratorExtension from './decoratorExtension';
jest.retryTimes(2);
describe('decoratorExtension', () => {
it('should highlight code blocks within tables', async () => {
// Regression test for https://github.com/laurent22/joplin/issues/9477
const editorText = `
left | right
--------|-------
\`foo\` | bar
`;
const editor = await createTestEditor(
editorText,
// Put the initial cursor at the start of "foo"
EditorSelection.cursor(editorText.indexOf('foo')),
['TableRow', 'InlineCode'],
[decoratorExtension],
);
const codeBlock = editor.contentDOM.querySelector('.cm-inlineCode');
expect(codeBlock.textContent).toBe('`foo`');
expect(codeBlock.parentElement.classList.contains('.cm-tableRow'));
});
});

View File

@@ -72,7 +72,7 @@ const taskMarkerDecoration = Decoration.mark({
attributes: { class: 'cm-taskMarker' },
});
type DecorationDescription = { pos: number; length: number; decoration: Decoration };
type DecorationDescription = { pos: number; length?: number; decoration: Decoration };
// Returns a set of [Decoration]s, associated with block syntax groups that require
// full-line styling.
@@ -87,7 +87,6 @@ const computeDecorations = (view: EditorView) => {
const line = view.state.doc.lineAt(pos);
decorations.push({
pos: line.from,
length: 0,
decoration,
});
@@ -186,23 +185,13 @@ const computeDecorations = (view: EditorView) => {
});
}
// Decorations need to be sorted in ascending order first by start position,
// then by length. Adding items to the RangeSetBuilder in an incorrect order
// causes an exception to be thrown.
decorations.sort((a, b) => {
const posComparison = a.pos - b.pos;
if (posComparison !== 0) {
return posComparison;
}
const lengthComparison = a.length - b.length;
return lengthComparison;
});
decorations.sort((a, b) => a.pos - b.pos);
// Items need to be added to a RangeSetBuilder in ascending order
const decorationBuilder = new RangeSetBuilder<Decoration>();
for (const { pos, length, decoration } of decorations) {
// Zero length => entire line
decorationBuilder.add(pos, pos + length, decoration);
// Null length => entire line
decorationBuilder.add(pos, pos + (length ?? 0), decoration);
}
return decorationBuilder.finish();
};

View File

@@ -1,7 +1,7 @@
import { markdown } from '@codemirror/lang-markdown';
import { GFM as GithubFlavoredMarkdownExt } from '@lezer/markdown';
import { indentUnit, syntaxTree } from '@codemirror/language';
import { SelectionRange, EditorSelection, EditorState, Extension } from '@codemirror/state';
import { SelectionRange, EditorSelection, EditorState } from '@codemirror/state';
import { EditorView } from '@codemirror/view';
import { MarkdownMathExtension } from '../markdown/markdownMathParser';
import forceFullParse from './forceFullParse';
@@ -10,10 +10,7 @@ import loadLangauges from './loadLanguages';
// Creates and returns a minimal editor with markdown extensions. Waits to return the editor
// until all syntax tree tags in `expectedSyntaxTreeTags` exist.
const createTestEditor = async (
initialText: string,
initialSelection: SelectionRange,
expectedSyntaxTreeTags: string[],
extraExtensions: Extension[] = [],
initialText: string, initialSelection: SelectionRange, expectedSyntaxTreeTags: string[],
): Promise<EditorView> => {
await loadLangauges();
@@ -26,7 +23,6 @@ const createTestEditor = async (
}),
indentUnit.of('\t'),
EditorState.tabSize.of(4),
extraExtensions,
],
});

View File

@@ -17,7 +17,7 @@
"@joplin/lib": "~2.13",
"@testing-library/react-hooks": "8.0.1",
"@types/jest": "29.5.5",
"@types/react": "18.2.33",
"@types/react": "18.2.34",
"@types/react-redux": "7.1.28",
"@types/styled-components": "5.1.29",
"jest": "29.7.0",
@@ -26,7 +26,7 @@
"typescript": "5.2.2"
},
"dependencies": {
"@codemirror/autocomplete": "6.9.2",
"@codemirror/autocomplete": "6.10.2",
"@codemirror/commands": "6.2.5",
"@codemirror/lang-cpp": "6.0.2",
"@codemirror/lang-html": "6.4.6",

View File

@@ -1,7 +1,7 @@
{
"name": "@joplin/fork-htmlparser2",
"description": "Fast & forgiving HTML/XML/RSS parser",
"version": "4.1.50",
"version": "4.1.49",
"author": "Felix Boehm <me@feedic.com>",
"publishConfig": {
"access": "public"
@@ -46,7 +46,7 @@
},
"devDependencies": {
"@types/jest": "29.5.5",
"@types/node": "18.18.7",
"@types/node": "18.18.8",
"@typescript-eslint/eslint-plugin": "6.7.2",
"@typescript-eslint/parser": "6.7.2",
"coveralls": "3.1.1",

View File

@@ -2,7 +2,7 @@
"name": "@joplin/fork-sax",
"description": "An evented streaming XML parser in JavaScript",
"author": "Isaac Z. Schlueter <i@izs.me> (http://blog.izs.me/)",
"version": "1.2.54",
"version": "1.2.53",
"main": "lib/sax.js",
"publishConfig": {
"access": "public"

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/fork-uslug",
"version": "1.0.15",
"version": "1.0.14",
"description": "A permissive slug generator that works with unicode.",
"author": "Jeremy Selier <jerem.selier@gmail.com>",
"publishConfig": {

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/htmlpack",
"version": "2.13.4",
"version": "2.13.3",
"description": "Pack an HTML file and all its linked resources into a single HTML file",
"main": "dist/index.js",
"types": "src/index.ts",
@@ -14,7 +14,7 @@
"author": "Laurent Cozic",
"license": "MIT",
"dependencies": {
"@joplin/fork-htmlparser2": "^4.1.50",
"@joplin/fork-htmlparser2": "^4.1.49",
"css": "3.0.0",
"datauri": "4.1.0",
"fs-extra": "11.1.1",

View File

@@ -237,7 +237,7 @@ export default class BaseApplication {
notes = await Tag.notes(parentId, options);
} else if (parentType === BaseModel.TYPE_SEARCH) {
const search = BaseModel.byId(state.searches, parentId);
notes = await SearchEngineUtils.notesForQuery(search.query_pattern, true);
notes = await SearchEngineUtils.notesForQuery(search.query_pattern, true, { appendWildCards: true });
const parsedQuery = await SearchEngine.instance().parseQuery(search.query_pattern);
highlightedWords = SearchEngine.instance().allParsedQueryTerms(parsedQuery);
} else if (parentType === BaseModel.TYPE_SMART_FILTER) {

View File

@@ -142,28 +142,20 @@ describe('import-enex-md-gen', () => {
expect(all[0].mime).toBe('application/zip');
});
// Disabled for now because the ENEX parser has become so error-tolerant
// that it's no longer possible to generate a note that would generate a
// failure.
// it('should keep importing notes when one of them is corrupted', async () => {
// const filePath = `${enexSampleBaseDir}/ImportTestCorrupt.enex`;
// const errors: any[] = [];
// const consoleSpy = jest.spyOn(console, 'warn').mockImplementation(jest.fn());
// await importEnex('', filePath, {
// onError: (error: any) => errors.push(error),
// });
// consoleSpy.mockRestore();
// const notes:NoteEntity[] = await Note.all();
// expect(notes.length).toBe(2);
// expect(notes.find(n => n.title === 'Note 1')).toBeTruthy();
// expect(notes.find(n => n.title === 'Note 3')).toBeTruthy();
it('should keep importing notes when one of them is corrupted', async () => {
const filePath = `${enexSampleBaseDir}/ImportTestCorrupt.enex`;
const errors: any[] = [];
await importEnex('', filePath, {
onError: (error: any) => errors.push(error),
});
const notes = await Note.all();
expect(notes.length).toBe(2);
// // Check that an error was recorded and that it includes the title
// // of the note, so that it can be found back by the user
// expect(errors.length).toBe(1);
// expect(errors[0].message.includes('Note 2')).toBe(true);
// });
// Check that an error was recorded and that it includes the title
// of the note, so that it can be found back by the user
expect(errors.length).toBe(1);
expect(errors[0].message.includes('Note 2')).toBe(true);
});
it('should throw an error and stop if the outer XML is invalid', async () => {
await expectThrow(async () => importEnexFile('invalid_html.enex'));
@@ -212,12 +204,4 @@ describe('import-enex-md-gen', () => {
expect(resource.title).toBe('app_images/resizable/961b875f-24ac-402f-9b76-37e2d4f03a6c/house_500.jpg.png');
});
it('should sanitize resource filenames with colons', async () => {
await importEnexFile('resource_filename_with_colons.enex');
const resource: ResourceEntity = (await Resource.all())[0];
expect(resource.filename).toBe('08.06.2014165855');
expect(resource.file_extension).toBe('2014165855');
expect(resource.title).toBe('08.06.2014 16:58:55');
});
});

View File

@@ -1239,14 +1239,6 @@ function drawTable(table: Section) {
continue;
}
if (typeof tr === 'string') {
// A <TABLE> tag should only have <TR> tags as direct children.
// However certain Evernote notes can contain other random tags
// such as empty DIVs. In that case we just skip the content.
// See test "table_with_invalid_content.html".
continue;
}
const isHeader = tr.isHeader;
const line = [];
const headerLine = [];
@@ -1254,11 +1246,6 @@ function drawTable(table: Section) {
for (let tdIndex = 0; tdIndex < tr.lines.length; tdIndex++) {
const td = tr.lines[tdIndex];
if (typeof td === 'string') {
// Same comment as above the <TR> tags.
continue;
}
if (flatRender) {
line.push(BLOCK_OPEN);

View File

@@ -9,7 +9,7 @@ import shim from './shim';
import { NoteEntity, ResourceEntity } from './services/database/types';
import { enexXmlToMd } from './import-enex-md-gen';
import { MarkupToHtml } from '@joplin/renderer';
import { fileExtension, friendlySafeFilename, safeFileExtension } from './path-utils';
import { fileExtension, friendlySafeFilename } from './path-utils';
const moment = require('moment');
const { wrapError } = require('./errorUtils');
const { enexXmlToHtml } = require('./import-enex-html-gen.js');
@@ -151,22 +151,18 @@ interface ExtractedNote extends NoteEntity {
tags?: string[];
title?: string;
bodyXml?: string;
// is_todo?: boolean;
}
// At this point we have the resource as it's been parsed from the XML, but
// additional processing needs to be done to get the final resource file, its
// size, MD5, etc.
// At this point we have the resource has it's been parsed from the XML, but additional
// processing needs to be done to get the final resource file, its size, MD5, etc.
async function processNoteResource(resource: ExtractedResource) {
const handleNoDataResource = async (resource: ExtractedResource, setId: boolean) => {
if (setId) resource.id = md5(Date.now() + Math.random());
if (!resource.hasData) {
// Some resources have no data, go figure, so we need a special case for this.
resource.id = md5(Date.now() + Math.random());
resource.size = 0;
resource.dataFilePath = `${Setting.value('tempDir')}/${resource.id}.empty`;
await fs.writeFile(resource.dataFilePath, '');
};
if (!resource.hasData) {
// Some resources have no data, go figure, so we need a special case for this.
await handleNoDataResource(resource, true);
} else {
if (resource.dataEncoding === 'base64') {
const decodedFilePath = `${resource.dataFilePath}.decoded`;
@@ -180,19 +176,16 @@ async function processNoteResource(resource: ExtractedResource) {
resource.size = stats.size;
if (!resource.id) {
// If no resource ID is present, the resource ID is actually the MD5
// of the data. This ID will match the "hash" attribute of the
// corresponding <en-media> tag. resourceId = md5(decodedData);
// If no resource ID is present, the resource ID is actually the MD5 of the data.
// This ID will match the "hash" attribute of the corresponding <en-media> tag.
// resourceId = md5(decodedData);
resource.id = await md5File(resource.dataFilePath);
}
if (!resource.id || !resource.size) {
// Don't throw an error because it happens semi-frequently,
// especially on notes that comes from the Evernote Web Clipper and
// we can't do anything about it. Previously we would throw the
// error "This resource was not added because it has no ID or no
// content".
await handleNoDataResource(resource, !resource.id);
const debugTemp = { ...resource };
debugTemp.data = debugTemp.data ? `${debugTemp.data.substr(0, 32)}...` : debugTemp.data;
throw new Error(`This resource was not added because it has no ID or no content: ${JSON.stringify(debugTemp)}`);
}
}
@@ -208,7 +201,7 @@ async function saveNoteResources(note: ExtractedNote) {
delete (toSave as any).dataFilePath;
delete (toSave as any).dataEncoding;
delete (toSave as any).hasData;
toSave.file_extension = resource.filename ? safeFileExtension(fileExtension(resource.filename)) : '';
toSave.file_extension = resource.filename ? fileExtension(resource.filename) : '';
// ENEX resource filenames can contain slashes, which may confuse other
// parts of the app, which expect this `filename` field to be safe.

View File

@@ -1,4 +1,4 @@
import { defaultFolderIcon, FolderEntity, FolderIcon, NoteEntity, ResourceEntity } from '../services/database/types';
import { defaultFolderIcon, FolderEntity, FolderIcon, NoteEntity } from '../services/database/types';
import BaseModel, { DeleteOptions } from '../BaseModel';
import time from '../time';
import { _ } from '../locale';
@@ -411,21 +411,14 @@ export default class Folder extends BaseItem {
// resume the process from the start (thus the loop) so that we deal
// with the right note/resource associations.
interface Row {
id: string;
share_id: string;
is_shared: number;
resource_is_shared: number;
}
for (let i = 0; i < 5; i++) {
// Find all resources where share_id is different from parent note
// share_id. Then update share_id on all these resources. Essentially it
// makes it match the resource share_id to the note share_id. At the
// same time we also process the is_shared property.
const rows = (await this.db().selectAll(`
SELECT r.id, n.share_id, n.is_shared, r.is_shared as resource_is_shared
const rows = await this.db().selectAll(`
SELECT r.id, n.share_id, n.is_shared
FROM note_resources nr
LEFT JOIN resources r ON nr.resource_id = r.id
LEFT JOIN notes n ON nr.note_id = n.id
@@ -433,7 +426,7 @@ export default class Folder extends BaseItem {
n.share_id != r.share_id
OR n.is_shared != r.is_shared
) AND nr.is_associated = 1
`)) as Row[];
`);
if (!rows.length) return;
@@ -441,7 +434,7 @@ export default class Folder extends BaseItem {
const resourceIds = rows.map(r => r.id);
interface NoteResourceRow {
interface Row {
resource_id: string;
note_id: string;
share_id: string;
@@ -457,9 +450,9 @@ export default class Folder extends BaseItem {
LEFT JOIN notes ON notes.id = note_resources.note_id
WHERE resource_id IN ('${resourceIds.join('\',\'')}')
AND is_associated = 1
`) as NoteResourceRow[];
`) as Row[];
const resourceIdToNotes: Record<string, NoteResourceRow[]> = {};
const resourceIdToNotes: Record<string, Row[]> = {};
for (const r of noteResourceAssociations) {
if (!resourceIdToNotes[r.resource_id]) resourceIdToNotes[r.resource_id] = [];
@@ -503,20 +496,13 @@ export default class Folder extends BaseItem {
} else {
// If all is good, we can set the share_id and is_shared
// property of the resource.
const now = Date.now();
for (const row of rows) {
const resource: ResourceEntity = {
await Resource.save({
id: row.id,
share_id: row.share_id || '',
is_shared: row.is_shared,
updated_time: now,
};
if (row.is_shared !== row.resource_is_shared) {
resource.blob_updated_time = now;
}
await Resource.save(resource, { autoTimestamp: false });
updated_time: Date.now(),
}, { autoTimestamp: false });
}
return;
}

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/lib",
"version": "2.13.4",
"version": "2.13.3",
"description": "Joplin Core library",
"author": "Laurent Cozic",
"homepage": "",
@@ -19,9 +19,9 @@
"@types/fs-extra": "11.0.3",
"@types/jest": "29.5.5",
"@types/js-yaml": "4.0.8",
"@types/node": "18.18.7",
"@types/node": "18.18.8",
"@types/node-rsa": "1.1.3",
"@types/react": "18.2.33",
"@types/react": "18.2.34",
"@types/uuid": "9.0.6",
"clean-html": "1.5.0",
"jest": "29.7.0",
@@ -31,14 +31,14 @@
"dependencies": {
"@aws-sdk/client-s3": "3.296.0",
"@aws-sdk/s3-request-presigner": "3.296.0",
"@joplin/fork-htmlparser2": "^4.1.50",
"@joplin/fork-sax": "^1.2.54",
"@joplin/fork-uslug": "^1.0.15",
"@joplin/htmlpack": "^2.13.4",
"@joplin/renderer": "^2.13.4",
"@joplin/turndown": "^4.0.72",
"@joplin/turndown-plugin-gfm": "^1.0.54",
"@joplin/utils": "^2.13.4",
"@joplin/fork-htmlparser2": "^4.1.49",
"@joplin/fork-sax": "^1.2.53",
"@joplin/fork-uslug": "^1.0.14",
"@joplin/htmlpack": "^2.13.3",
"@joplin/renderer": "^2.13.3",
"@joplin/turndown": "^4.0.71",
"@joplin/turndown-plugin-gfm": "^1.0.53",
"@joplin/utils": "^2.13.3",
"@types/nanoid": "3.0.0",
"async-mutex": "0.4.0",
"base-64": "1.0.0",

View File

@@ -39,9 +39,6 @@ export function isHidden(path: string) {
return b[0] === '.';
}
// Note that this function only sanitizes a file extension - it does NOT extract
// the file extension from a filename. So the way you'd normally call this is
// `safeFileExtension(fileExtension(filename))`
export function safeFileExtension(e: string, maxLength: number = null) {
// In theory the file extension can have any length but in practice Joplin
// expects a fixed length, so we limit it to 20 which should cover most cases.

View File

@@ -63,6 +63,11 @@ type RequestNote = {
stylesheets: any;
};
type FetchOptions = {
timeout?: number;
maxRedirects?: number;
};
async function requestNoteToNote(requestNote: RequestNote): Promise<NoteEntity> {
const output: any = {
title: requestNote.title ? requestNote.title : '',
@@ -184,7 +189,7 @@ async function tryToGuessExtFromMimeType(response: any, mediaPath: string) {
return newMediaPath;
}
export async function downloadMediaFile(url: string /* , allowFileProtocolImages */) {
export async function downloadMediaFile(url: string, fetchOptions?: FetchOptions) {
logger.info('Downloading media file', url);
const tempDir = Setting.value('tempDir');
@@ -225,7 +230,7 @@ export async function downloadMediaFile(url: string /* , allowFileProtocolImages
const localPath = fileUriToPath(url);
await shim.fsDriver().copy(localPath, mediaPath);
} else {
const response = await shim.fetchBlob(url, { path: mediaPath, maxRetry: 1 });
const response = await shim.fetchBlob(url, { path: mediaPath, maxRetry: 1, ...fetchOptions });
// If we could not find the file extension from the URL, try to get it
// now based on the Content-Type header.
@@ -238,13 +243,13 @@ export async function downloadMediaFile(url: string /* , allowFileProtocolImages
}
}
async function downloadMediaFiles(urls: string[] /* , allowFileProtocolImages:boolean */) {
async function downloadMediaFiles(urls: string[], fetchOptions?: FetchOptions) {
const PromisePool = require('es6-promise-pool');
const output: any = {};
const downloadOne = async (url: string) => {
const mediaPath = await downloadMediaFile(url); // , allowFileProtocolImages);
const mediaPath = await downloadMediaFile(url, fetchOptions); // , allowFileProtocolImages);
if (mediaPath) output[url] = { path: mediaPath, originalUrl: url };
};
@@ -369,14 +374,14 @@ async function attachImageFromDataUrl(note: any, imageDataUrl: string, cropRect:
return await shim.attachFileToNote(note, tempFilePath);
}
export const extractNoteFromHTML = async (requestNote: RequestNote, requestId: number, imageSizes: any) => {
export const extractNoteFromHTML = async (requestNote: RequestNote, requestId: number, imageSizes: any, fetchOptions?: FetchOptions) => {
const note = await requestNoteToNote(requestNote);
const mediaUrls = extractMediaUrls(note.markup_language, note.body);
logger.info(`Request (${requestId}): Downloading media files: ${mediaUrls.length}`);
const mediaFiles = await downloadMediaFiles(mediaUrls); // , allowFileProtocolImages);
const mediaFiles = await downloadMediaFiles(mediaUrls, fetchOptions); // , allowFileProtocolImages);
logger.info(`Request (${requestId}): Creating resources from paths: ${Object.getOwnPropertyNames(mediaFiles).length}`);

View File

@@ -5,7 +5,7 @@ import { ErrorBadRequest, ErrorMethodNotAllowed } from '../utils/errors';
import requestFields from '../utils/requestFields';
import collectionToPaginatedResults from '../utils/collectionToPaginatedResults';
import BaseItem from '../../../models/BaseItem';
import SearchEngineUtils from '../../searchengine/SearchEngineUtils';
import SearchEngineUtils, { NotesForQueryOptions } from '../../searchengine/SearchEngineUtils';
export default async function(request: Request) {
if (request.method !== 'GET') throw new ErrorMethodNotAllowed();
@@ -28,7 +28,11 @@ export default async function(request: Request) {
options.caseInsensitive = true;
results = await ModelClass.all(options);
} else {
results = await SearchEngineUtils.notesForQuery(query, false, defaultLoadOptions(request, ModelType.Note));
const options: NotesForQueryOptions = {
...defaultLoadOptions(request, ModelType.Note),
appendWildCards: true,
};
results = await SearchEngineUtils.notesForQuery(query, false, options);
}
return collectionToPaginatedResults(modelType, results, request);

View File

@@ -1,9 +1,9 @@
import Note from '../../models/Note';
import { createFolderTree, encryptionService, loadEncryptionMasterKey, msleep, resourceService, setupDatabaseAndSynchronizer, simulateReadOnlyShareEnv, supportDir, switchClient, synchronizerStart } from '../../testing/test-utils';
import { createFolderTree, encryptionService, loadEncryptionMasterKey, msleep, resourceService, setupDatabaseAndSynchronizer, simulateReadOnlyShareEnv, supportDir, switchClient } from '../../testing/test-utils';
import ShareService from './ShareService';
import reducer, { defaultState } from '../../reducer';
import { createStore } from 'redux';
import { NoteEntity, ResourceEntity } from '../database/types';
import { NoteEntity } from '../database/types';
import Folder from '../../models/Folder';
import { setEncryptionEnabled, setPpk } from '../synchronizer/syncInfoUtils';
import { generateKeyPair } from '../e2ee/ppk';
@@ -18,7 +18,6 @@ import BaseItem from '../../models/BaseItem';
import ResourceService from '../ResourceService';
import Setting from '../../models/Setting';
import { ModelType } from '../../BaseModel';
import { remoteNotesFoldersResources } from '../../testing/test-utils-synchronizer';
interface TestShareFolderServiceOptions {
master_key_id?: string;
@@ -37,18 +36,6 @@ function mockService(api: any) {
return service;
}
const mockServiceForNoteSharing = () => {
return mockService({
exec: (method: string, path = '', _query: Record<string, any> = null, _body: any = null, _headers: any = null, _options: any = null): Promise<any> => {
if (method === 'GET' && path === 'api/shares') return { items: [] } as any;
return null;
},
personalizedUserContentBaseUrl(_userId: string) {
},
});
};
describe('ShareService', () => {
beforeEach(async () => {
@@ -58,7 +45,15 @@ describe('ShareService', () => {
it('should not change the note user timestamps when sharing or unsharing', async () => {
let note = await Note.save({});
const service = mockServiceForNoteSharing();
const service = mockService({
exec: (method: string, path = '', _query: Record<string, any> = null, _body: any = null, _headers: any = null, _options: any = null): Promise<any> => {
if (method === 'GET' && path === 'api/shares') return { items: [] } as any;
return null;
},
personalizedUserContentBaseUrl(_userId: string) {
},
});
await msleep(1);
await service.shareNote(note.id, false);
@@ -87,46 +82,6 @@ describe('ShareService', () => {
}
});
it('should not encrypt items that are shared', async () => {
const folder = await Folder.save({});
const note = await Note.save({ parent_id: folder.id });
await shim.attachFileToNote(note, testImagePath);
const service = mockServiceForNoteSharing();
setEncryptionEnabled(true);
await loadEncryptionMasterKey();
await synchronizerStart();
let previousBlobUpdatedTime = Infinity;
{
const allItems = await remoteNotesFoldersResources();
expect(allItems.map(it => it.encryption_applied)).toEqual([1, 1, 1]);
previousBlobUpdatedTime = allItems.find(it => it.type_ === ModelType.Resource).blob_updated_time;
}
await service.shareNote(note.id, false);
await msleep(1);
await Folder.updateAllShareIds(resourceService());
await synchronizerStart();
{
const allItems = await remoteNotesFoldersResources();
expect(allItems.find(it => it.type_ === ModelType.Note).encryption_applied).toBe(0);
expect(allItems.find(it => it.type_ === ModelType.Folder).encryption_applied).toBe(1);
const resource: ResourceEntity = allItems.find(it => it.type_ === ModelType.Resource);
expect(resource.encryption_applied).toBe(0);
// Indicates that both the metadata and blob have been decrypted on
// the sync target.
expect(resource.blob_updated_time).toBe(resource.updated_time);
expect(resource.blob_updated_time).toBeGreaterThan(previousBlobUpdatedTime);
}
});
// eslint-disable-next-line @typescript-eslint/ban-types -- Old code before rule was applied
function testShareFolderService(extraExecHandlers: Record<string, Function> = {}, options: TestShareFolderServiceOptions = {}) {
return mockService({

View File

@@ -460,6 +460,11 @@ function shimInit(options = null) {
if (!options.method) options.method = 'GET';
// if (!('maxRetry' in options)) options.maxRetry = 5;
// 21 maxRedirects is the default amount from follow-redirects library
// 20 seems to be the max amount that most popular browsers will allow
if (!options.maxRedirects) options.maxRedirects = 21;
if (!options.timeout) options.timeout = undefined;
const urlParse = require('url').parse;
url = urlParse(url.trim());
@@ -490,6 +495,8 @@ function shimInit(options = null) {
method: method,
path: url.pathname + (url.query ? `?${url.query}` : ''),
headers: headers,
timeout: options.timeout,
maxRedirects: options.maxRedirects,
};
const resolvedProxyUrl = resolveProxyUrl(proxySettings.proxyUrl);
@@ -551,6 +558,10 @@ function shimInit(options = null) {
});
});
request.on('timeout', () => {
request.destroy(new Error(`Request timed out. Timeout value: ${requestOptions.timeout}ms.`));
});
request.on('error', (error) => {
cleanUpOnError(error);
});

View File

@@ -21,7 +21,7 @@
"devDependencies": {
"@types/jest": "29.5.5",
"@types/pdfjs-dist": "2.10.378",
"@types/react": "18.2.33",
"@types/react": "18.2.34",
"@types/react-dom": "18.2.14",
"@types/styled-components": "5.1.29",
"babel-jest": "29.7.0",
@@ -30,7 +30,7 @@
"jest-environment-jsdom": "29.7.0",
"style-loader": "3.3.3",
"ts-jest": "29.1.1",
"ts-loader": "9.4.4",
"ts-loader": "9.5.0",
"typescript": "5.2.2",
"webpack": "5.74.0",
"webpack-cli": "4.10.0"

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/plugin-repo-cli",
"version": "2.13.4",
"version": "2.13.3",
"description": "",
"main": "index.js",
"bin": "./dist/index.js",
@@ -18,9 +18,9 @@
"author": "",
"license": "AGPL-3.0-or-later",
"dependencies": {
"@joplin/lib": "^2.13.4",
"@joplin/tools": "^2.13.4",
"@joplin/utils": "^2.13.4",
"@joplin/lib": "^2.13.3",
"@joplin/tools": "^2.13.3",
"@joplin/utils": "^2.13.3",
"fs-extra": "11.1.1",
"gh-release-assets": "2.0.1",
"node-fetch": "2.6.7",
@@ -30,7 +30,7 @@
"devDependencies": {
"@types/fs-extra": "11.0.3",
"@types/jest": "29.5.5",
"@types/node": "18.18.7",
"@types/node": "18.18.8",
"jest": "29.7.0",
"source-map-loader": "4.0.1",
"typescript": "5.2.2",

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/react-native-saf-x",
"version": "2.13.4",
"version": "2.13.3",
"description": "a module to help work with scoped storages on android easily",
"main": "src/index",
"react-native": "src/index",

View File

@@ -43,22 +43,12 @@ function stringifyKatexOptions(options: any) {
// \prob: {tokens: Array(12), numArgs: 1}
// \expval: {tokens: Array(14), numArgs: 2}
// \wf: {tokens: Array(6), numArgs: 0}
// \@eqnsw: "1"
//
// Additionally, some KaTeX macros don't follow this general format. For example
// \@eqnsw: "1"
// is created by \begin{align}...\end{align} environments, and doesn't have a "tokens" property.
if (options.macros) {
const toSerialize: any = {};
for (const k of Object.keys(options.macros)) {
const macro = options.macros[k];
if (typeof macro === 'string') {
toSerialize[k] = `${macro}_string`;
} else {
const macroText: string[] = macro.tokens.map((t: any) => t.text);
toSerialize[k] = `${macroText.join('')}_${macro.numArgs}`;
}
const macroText: string[] = options.macros[k].tokens.map((t: any) => t.text);
toSerialize[k] = `${macroText.join('')}_${options.macros[k].numArgs}`;
}
newOptions.macros = toSerialize;
}

View File

@@ -1,4 +1,4 @@
import htmlUtils, { extractHtmlBody } from './htmlUtils';
import htmlUtils, { extractHtmlBody, htmlDocIsImageOnly } from './htmlUtils';
describe('htmlUtils', () => {
@@ -51,4 +51,39 @@ describe('htmlUtils', () => {
}
});
test('should tell if an HTML document is an image only', () => {
const testCases: [string, boolean][] = [
[
// This is the kind of HTML that's pasted when copying an image from Chrome
'<meta charset=\'utf-8\'>\n<img src="https://example.com/img.png"/>',
true,
],
[
'',
false,
],
[
'<img src="https://example.com/img.png"/>',
true,
],
[
'<img src="https://example.com/img.png"/><img src="https://example.com/img.png"/>',
false,
],
[
'<img src="https://example.com/img.png"/><p>Some text</p>',
false,
],
[
'<img src="https://example.com/img.png"/> Some text',
false,
],
];
for (const [input, expected] of testCases) {
const actual = htmlDocIsImageOnly(input);
expect(actual).toBe(expected);
}
});
});

View File

@@ -404,4 +404,33 @@ export const extractHtmlBody = (html: string) => {
return bodyFound ? output.join('') : html;
};
export const htmlDocIsImageOnly = (html: string) => {
let imageCount = 0;
let nonImageFound = false;
let textFound = false;
const parser = new htmlparser2.Parser({
onopentag: (name: string) => {
if (name === 'img') {
imageCount++;
} else if (['meta'].includes(name)) {
// We allow these tags since they don't print anything
} else {
nonImageFound = true;
}
},
ontext: (text: string) => {
if (text.trim()) textFound = true;
},
});
parser.write(html);
parser.end();
return imageCount === 1 && !nonImageFound && !textFound;
};
export default new HtmlUtils();

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/renderer",
"version": "2.13.4",
"version": "2.13.3",
"description": "The Joplin note renderer, used the mobile and desktop application",
"repository": "https://github.com/laurent22/joplin/tree/dev/packages/renderer",
"main": "index.js",
@@ -21,19 +21,19 @@
"devDependencies": {
"@types/jest": "29.5.5",
"@types/markdown-it": "13.0.5",
"@types/node": "18.18.7",
"@types/node": "18.18.8",
"jest": "29.7.0",
"jest-environment-jsdom": "29.7.0",
"ts-jest": "29.1.1",
"typescript": "5.2.2"
},
"dependencies": {
"@joplin/fork-htmlparser2": "^4.1.50",
"@joplin/fork-uslug": "^1.0.15",
"@joplin/utils": "^2.13.4",
"@joplin/fork-htmlparser2": "^4.1.49",
"@joplin/fork-uslug": "^1.0.14",
"@joplin/utils": "^2.13.3",
"font-awesome-filetypes": "2.1.0",
"fs-extra": "11.1.1",
"highlight.js": "11.8.0",
"highlight.js": "11.9.0",
"html-entities": "1.4.0",
"json-stringify-safe": "5.0.1",
"katex": "0.16.9",

View File

@@ -5,7 +5,6 @@
"**/*.tsx",
],
"exclude": [
"**/node_modules",
"**/*.test.ts",
"**/node_modules"
],
}

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/server",
"version": "2.13.4",
"version": "2.13.5",
"private": true,
"scripts": {
"start-dev": "yarn run build && JOPLIN_IS_TESTING=1 nodemon --config nodemon.json --ext ts,js,mustache,css,tsx dist/app.js --env dev",
@@ -40,7 +40,7 @@
"jquery": "3.7.1",
"knex": "2.5.1",
"koa": "2.14.2",
"ldapts": "7.0.5",
"ldapts": "7.0.6",
"markdown-it": "13.0.2",
"mustache": "4.2.0",
"nanoid": "2.1.11",
@@ -52,7 +52,7 @@
"pretty-bytes": "5.6.0",
"prettycron": "0.10.0",
"query-string": "7.1.3",
"rate-limiter-flexible": "2.4.2",
"rate-limiter-flexible": "3.0.3",
"raw-body": "2.5.2",
"sqlite3": "5.1.6",
"stripe": "8.222.0",

View File

@@ -178,6 +178,14 @@ describe('ChangeModel', () => {
expect(changeCount).toBe(SqliteMaxVariableNum);
});
test('should tell if there are more changes', async () => {
const { user } = await createUserAndSession(1, true);
await models().item().makeTestItems(user.id, 500);
const result = await models().change().delta(user.id, { limit: 100 });
expect(result.has_more).toBe(true);
});
test('should delete old changes', async () => {
// Create the following events:
//

View File

@@ -139,8 +139,6 @@ export default class ChangeModel extends BaseModel<Change> {
// as the `changes` table grew. So it is now split into two queries
// merged by a UNION ALL.
const subQueryLimit = Math.ceil(limit / 2);
const fields = [
'id',
'item_id',
@@ -169,7 +167,7 @@ export default class ChangeModel extends BaseModel<Change> {
userId,
];
if (!doCountQuery) subParams1.push(subQueryLimit);
if (!doCountQuery) subParams1.push(limit);
const subQuery2 = `
SELECT ${fieldsSql}
@@ -187,7 +185,7 @@ export default class ChangeModel extends BaseModel<Change> {
userId,
];
if (!doCountQuery) subParams2.push(subQueryLimit);
if (!doCountQuery) subParams2.push(limit);
let query: Knex.Raw<any> = null;

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/tools",
"version": "2.13.4",
"version": "2.13.3",
"description": "Various tools for Joplin",
"main": "index.js",
"author": "Laurent Cozic",
@@ -20,9 +20,9 @@
},
"license": "AGPL-3.0-or-later",
"dependencies": {
"@joplin/lib": "^2.13.4",
"@joplin/renderer": "^2.13.4",
"@joplin/utils": "^2.13.4",
"@joplin/lib": "^2.13.3",
"@joplin/renderer": "^2.13.3",
"@joplin/utils": "^2.13.3",
"compare-versions": "6.1.0",
"dayjs": "1.11.10",
"execa": "4.1.0",
@@ -43,15 +43,15 @@
},
"devDependencies": {
"@docusaurus/plugin-sitemap": "2.4.3",
"@joplin/fork-htmlparser2": "^4.1.50",
"@joplin/fork-htmlparser2": "^4.1.49",
"@rmp135/sql-ts": "1.18.0",
"@types/fs-extra": "11.0.3",
"@types/jest": "29.5.5",
"@types/js-yaml": "4.0.8",
"@types/markdown-it": "13.0.5",
"@types/mustache": "4.2.4",
"@types/node": "18.18.7",
"@types/node-fetch": "2.6.7",
"@types/node": "18.18.8",
"@types/node-fetch": "2.6.8",
"@types/yargs": "17.0.29",
"gettext-extractor": "3.8.0",
"gulp": "4.0.2",
@@ -61,7 +61,7 @@
"rss": "1.2.2",
"sass": "1.69.5",
"sqlite3": "5.1.6",
"style-to-js": "1.1.8",
"style-to-js": "1.1.9",
"typescript": "5.2.2"
},
"gitHead": "05a29b450962bf05a8642bbd39446a1f679a96ba"

View File

@@ -1 +1 @@
{"processedReleases":{"v2.13.1":true,"v2.13.2":true,"v2.13.3":true,"v2.13.4":true,"v2.13.5":true}}
{"processedReleases":{"v2.13.1":true,"v2.13.2":true,"v2.13.3":true,"v2.13.4":true,"v2.13.5":true,"v2.13.6":true}}

View File

@@ -4,7 +4,7 @@
"publishConfig": {
"access": "public"
},
"version": "1.0.54",
"version": "1.0.53",
"author": "Dom Christie",
"main": "lib/turndown-plugin-gfm.cjs.js",
"devDependencies": {

View File

@@ -74,8 +74,8 @@ rules.tableRow = {
rules.table = {
// Only convert tables that can result in valid Markdown
// Other tables are kept as HTML using `keep` (see below).
filter: function (node, options) {
return node.nodeName === 'TABLE' && !tableShouldBeHtml(node, options);
filter: function (node) {
return node.nodeName === 'TABLE' && !tableShouldBeHtml(node);
},
replacement: function (content, node) {
@@ -174,7 +174,7 @@ const nodeContains = (node, types) => {
return false;
}
const tableShouldBeHtml = (tableNode, options) => {
const tableShouldBeHtml = (tableNode, preserveNestedTables) => {
const possibleTags = [
'UL',
'OL',
@@ -193,7 +193,7 @@ const tableShouldBeHtml = (tableNode, options) => {
// that's made of HTML tables. In that case we have this logic of removing the
// outer table and keeping only the inner ones. For the Rich Text editor
// however we always want to keep nested tables.
if (options.preserveNestedTables) possibleTags.push('TABLE');
if (preserveNestedTables) possibleTags.push('TABLE');
return nodeContains(tableNode, 'code') ||
nodeContains(tableNode, possibleTags);
@@ -249,7 +249,7 @@ export default function tables (turndownService) {
isCodeBlock_ = turndownService.isCodeBlock;
turndownService.keep(function (node) {
if (node.nodeName === 'TABLE' && tableShouldBeHtml(node, turndownService.options)) return true;
if (node.nodeName === 'TABLE' && tableShouldBeHtml(node, turndownService.options.preserveNestedTables)) return true;
return false;
});
for (var key in rules) turndownService.addRule(key, rules[key])

View File

@@ -1,7 +1,7 @@
{
"name": "@joplin/turndown",
"description": "A library that converts HTML to Markdown",
"version": "4.0.72",
"version": "4.0.71",
"author": "Dom Christie",
"main": "lib/turndown.cjs.js",
"publishConfig": {

View File

@@ -1,6 +1,6 @@
{
"name": "@joplin/utils",
"version": "2.13.4",
"version": "2.13.3",
"description": "Utilities for Joplin",
"repository": "https://github.com/laurent22/joplin/tree/dev/packages/utils",
"exports": {
@@ -38,7 +38,7 @@
"devDependencies": {
"@types/fs-extra": "11.0.3",
"@types/jest": "29.5.5",
"@types/node-fetch": "2.6.7",
"@types/node-fetch": "2.6.8",
"jest": "29.7.0",
"ts-jest": "29.1.1"
},

View File

@@ -1,20 +1,5 @@
# Joplin Android Changelog
## [android-v2.13.10](https://github.com/laurent22/joplin/releases/tag/android-v2.13.10) (Pre-release) - 2023-12-01T11:16:17Z
- Improved: Drawing: Revert recent changes to input system (#9426) (#9427 by Henry Heino)
## [android-v2.13.9](https://github.com/laurent22/joplin/releases/tag/android-v2.13.9) (Pre-release) - 2023-11-30T17:55:54Z
- Improved: Don't attach empty drawings when a user exits without saving (#9386) (#9377 by Henry Heino)
- Fixed: Fix tooltips don't disappear on some devices (upgrade to js-draw 1.13.2) (#9401) (#9374 by Henry Heino)
## [android-v2.13.8](https://github.com/laurent22/joplin/releases/tag/android-v2.13.8) (Pre-release) - 2023-11-26T12:37:00Z
- Fixed: Fix to-dos options toggle don't toggle a rerender (#9364) (#9361 by [@pedr](https://github.com/pedr))
- Fixed: Fix new note/to-do buttons not visible on app startup in some cases (#9329) (#9328 by Henry Heino)
- Fixed: Sidebar is not dismissed when creating a note (#9376)
## [android-v2.13.7](https://github.com/laurent22/joplin/releases/tag/android-v2.13.7) (Pre-release) - 2023-11-16T13:17:53Z
- Improved: Add more space between settings title and description (#9270) (#9258 by Henry Heino)

View File

@@ -1,11 +1,5 @@
# Joplin Terminal App Changelog
## [cli-v2.13.2](https://github.com/laurent22/joplin/releases/tag/cli-v2.13.2) - 2023-11-30T18:11:38Z
- Improved: Updated packages mermaid (v10.5.1), sass (v1.69.5)
- Fixed: Import of inter-linked md files has incorrect notebook structure (#9269) (#9151 by [@pedr](https://github.com/pedr))
- Fixed: Work around WebDAV sync issues over ipv6 (#9286) (#8788 by Henry Heino)
## [cli-v2.13.1](https://github.com/laurent22/joplin/releases/tag/cli-v2.13.1) - 2023-11-09T20:08:17Z
- Improved: Allow modifying a resource metadata only when synchronising (#9114)

View File

@@ -1,5 +1,16 @@
# Joplin Desktop Changelog
## [v2.13.6](https://github.com/laurent22/joplin/releases/tag/v2.13.6) (Pre-release) - 2023-11-17T19:24:03Z
- Improved: Improve toolbar button wrapping on RTE ([ccf1c8e](https://github.com/laurent22/joplin/commit/ccf1c8e))
- Improved: Install script: Work around unprivileged user namespace restrictions by adding the --no-sandbox flag to the launcher ([#9137](https://github.com/laurent22/joplin/issues/9137)) ([#9136](https://github.com/laurent22/joplin/issues/9136) by Henry Heino)
- Improved: Make settings tabs focusable by keyboard ([#9253](https://github.com/laurent22/joplin/issues/9253)) ([#9250](https://github.com/laurent22/joplin/issues/9250) by Henry Heino)
- Improved: Preserve nested tables in RTE ([#9293](https://github.com/laurent22/joplin/issues/9293))
- Improved: Updated packages mermaid (v10.5.1), sass (v1.69.5)
- Fixed: Fixed import error report ([6211606](https://github.com/laurent22/joplin/commit/6211606))
- Fixed: Import of inter-linked md files has incorrect notebook structure ([#9269](https://github.com/laurent22/joplin/issues/9269)) ([#9151](https://github.com/laurent22/joplin/issues/9151) by [@pedr](https://github.com/pedr))
- Fixed: Work around WebDAV sync issues over ipv6 ([#9286](https://github.com/laurent22/joplin/issues/9286)) ([#8788](https://github.com/laurent22/joplin/issues/8788) by Henry Heino)
## [v2.13.5](https://github.com/laurent22/joplin/releases/tag/v2.13.5) (Pre-release) - 2023-11-09T20:24:09Z
- New: Plugins: Add support for getting plugin settings from a Markdown renderer ([8be22ed](https://github.com/laurent22/joplin/commit/8be22ed))

View File

@@ -1,20 +1,5 @@
# Joplin iOS Changelog
## [ios-v12.13.10](https://github.com/laurent22/joplin/releases/tag/ios-v12.13.10) - 2023-12-01T12:07:57Z
- Improved: Drawing: Revert recent changes to input system (#9426) (#9427 by Henry Heino)
## [ios-v12.13.9](https://github.com/laurent22/joplin/releases/tag/ios-v12.13.9) - 2023-11-30T17:56:37Z
- Improved: Don't attach empty drawings when a user exits without saving (#9386) (#9377 by Henry Heino)
- Fixed: Fix tooltips don't disappear on some devices (upgrade to js-draw 1.13.2) (#9401) (#9374 by Henry Heino)
## [ios-v12.13.8](https://github.com/laurent22/joplin/releases/tag/ios-v12.13.8) - 2023-11-26T12:54:44Z
- Fixed: Fix to-dos options toggle don't toggle a rerender (#9364) (#9361 by [@pedr](https://github.com/pedr))
- Fixed: Fix new note/to-do buttons not visible on app startup in some cases (#9329) (#9328 by Henry Heino)
- Fixed: Sidebar is not dismissed when creating a note (#9376)
## [ios-v12.13.7](https://github.com/laurent22/joplin/releases/tag/ios-v12.13.7) - 2023-11-16T13:37:03Z
- Improved: Add more space between settings title and description (#9270) (#9258 by Henry Heino)

View File

@@ -1,5 +1,12 @@
# Joplin Server Changelog
## [server-v2.13.5](https://github.com/laurent22/joplin/releases/tag/server-v2.13.5) - 2023-11-19T09:33:53Z
- Improved: Increase number of items that are returned during sync (767bf9f)
- Improved: Updated packages highlight.js (v11.9.0), ldapts (v7.0.6), sass (v1.69.5)
- Fixed: Fix severe performance issue for certain delta calls (f698068)
- Fixed: Fixed issue with sync not immediately returning all items in certain cases (87aeffa)
## [server-v2.13.4](https://github.com/laurent22/joplin/releases/tag/server-v2.13.4) - 2023-11-15T15:30:19Z
- New: Added LDAP authentication (#9150 by Marco Rombach)

458
yarn.lock
View File

@@ -3978,9 +3978,9 @@ __metadata:
languageName: node
linkType: hard
"@codemirror/autocomplete@npm:6.9.2":
version: 6.9.2
resolution: "@codemirror/autocomplete@npm:6.9.2"
"@codemirror/autocomplete@npm:6.10.2":
version: 6.10.2
resolution: "@codemirror/autocomplete@npm:6.10.2"
dependencies:
"@codemirror/language": ^6.0.0
"@codemirror/state": ^6.0.0
@@ -3991,7 +3991,7 @@ __metadata:
"@codemirror/state": ^6.0.0
"@codemirror/view": ^6.0.0
"@lezer/common": ^1.0.0
checksum: 8bdf06c2b4eb1cd6c8a6e1df2eb5c92011fda0bc8970f9d68cc8dad8e4f9d3c243aaa3e42505252af542be8bbaf0a3ed7e23a6b7f603171077cc36845e188190
checksum: 360cea6a87ae9c4e3c996903f636a8f47f8ea6cd44504181e69dd8ccf666bad3e8cc6d8935e0eedd8aa118fdfe86ea78f41bc15288f3a7517dbb87115e057563
languageName: node
linkType: hard
@@ -5696,6 +5696,13 @@ __metadata:
languageName: node
linkType: hard
"@gar/promisify@npm:^1.1.3":
version: 1.1.3
resolution: "@gar/promisify@npm:1.1.3"
checksum: 4059f790e2d07bf3c3ff3e0fec0daa8144fe35c1f6e0111c9921bd32106adaa97a4ab096ad7dab1e28ee6a9060083c4d1a4ada42a7f5f3f7a96b8812e2b757c1
languageName: node
linkType: hard
"@github/browserslist-config@npm:^1.0.0":
version: 1.0.0
resolution: "@github/browserslist-config@npm:1.0.0"
@@ -6213,12 +6220,12 @@ __metadata:
"@joplin/renderer": ~2.13
"@joplin/tools": ~2.13
"@joplin/utils": ~2.13
"@playwright/test": 1.38.1
"@playwright/test": 1.39.0
"@testing-library/react-hooks": 8.0.1
"@types/jest": 29.5.5
"@types/mustache": 4.2.4
"@types/node": 18.18.7
"@types/react": 18.2.33
"@types/node": 18.18.8
"@types/react": 18.2.34
"@types/react-redux": 7.1.28
"@types/styled-components": 5.1.29
async-mutex: 0.4.0
@@ -6234,7 +6241,7 @@ __metadata:
fs-extra: 11.1.1
glob: 10.3.10
gulp: 4.0.2
highlight.js: 11.8.0
highlight.js: 11.9.0
immer: 7.0.15
jest: 29.7.0
jest-environment-jsdom: 29.7.0
@@ -6293,20 +6300,20 @@ __metadata:
"@joplin/renderer": ~2.13
"@joplin/tools": ~2.13
"@joplin/utils": ~2.13
"@js-draw/material-icons": 1.14.0
"@js-draw/material-icons": 1.11.2
"@lezer/highlight": 1.1.4
"@react-native-community/clipboard": 1.5.1
"@react-native-community/datetimepicker": 7.6.1
"@react-native-community/geolocation": 3.1.0
"@react-native-community/netinfo": 9.4.1
"@react-native-community/netinfo": 9.4.2
"@react-native-community/push-notification-ios": 1.11.0
"@react-native-community/slider": 4.4.3
"@testing-library/jest-native": 5.4.3
"@testing-library/react-native": 12.3.1
"@testing-library/react-native": 12.3.2
"@tsconfig/react-native": 2.0.2
"@types/fs-extra": 11.0.3
"@types/jest": 29.5.5
"@types/react": 18.2.33
"@types/react": 18.2.34
"@types/react-native": 0.70.6
"@types/react-redux": 7.1.28
"@types/tar-stream": 2.2.3
@@ -6323,7 +6330,7 @@ __metadata:
jest: 29.7.0
jest-environment-jsdom: 29.7.0
jetifier: 2.0.0
js-draw: 1.14.0
js-draw: 1.11.2
jsc-android: 241213.1.0
jsdom: 22.1.0
lodash: 4.17.21
@@ -6332,7 +6339,7 @@ __metadata:
nodemon: 3.0.1
path-browserify: 1.0.1
prop-types: 15.8.1
punycode: 2.3.0
punycode: 2.3.1
react: 18.2.0
react-native: 0.71.10
react-native-camera: 4.2.1
@@ -6374,7 +6381,7 @@ __metadata:
tar-stream: 3.1.6
timers: 0.1.1
ts-jest: 29.1.1
ts-loader: 9.4.4
ts-loader: 9.5.0
ts-node: 10.9.1
typescript: 5.2.2
uglify-js: 3.17.4
@@ -6408,7 +6415,7 @@ __metadata:
version: 0.0.0-use.local
resolution: "@joplin/editor@workspace:packages/editor"
dependencies:
"@codemirror/autocomplete": 6.9.2
"@codemirror/autocomplete": 6.10.2
"@codemirror/commands": 6.2.5
"@codemirror/lang-cpp": 6.0.2
"@codemirror/lang-html": 6.4.6
@@ -6427,7 +6434,7 @@ __metadata:
"@replit/codemirror-vim": 6.0.14
"@testing-library/react-hooks": 8.0.1
"@types/jest": 29.5.5
"@types/react": 18.2.33
"@types/react": 18.2.34
"@types/react-redux": 7.1.28
"@types/styled-components": 5.1.29
jest: 29.7.0
@@ -6437,12 +6444,12 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/fork-htmlparser2@^4.1.50, @joplin/fork-htmlparser2@workspace:packages/fork-htmlparser2":
"@joplin/fork-htmlparser2@^4.1.49, @joplin/fork-htmlparser2@workspace:packages/fork-htmlparser2":
version: 0.0.0-use.local
resolution: "@joplin/fork-htmlparser2@workspace:packages/fork-htmlparser2"
dependencies:
"@types/jest": 29.5.5
"@types/node": 18.18.7
"@types/node": 18.18.8
"@typescript-eslint/eslint-plugin": 6.7.2
"@typescript-eslint/parser": 6.7.2
coveralls: 3.1.1
@@ -6458,7 +6465,7 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/fork-sax@^1.2.54, @joplin/fork-sax@workspace:packages/fork-sax":
"@joplin/fork-sax@^1.2.53, @joplin/fork-sax@workspace:packages/fork-sax":
version: 0.0.0-use.local
resolution: "@joplin/fork-sax@workspace:packages/fork-sax"
dependencies:
@@ -6467,7 +6474,7 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/fork-uslug@^1.0.15, @joplin/fork-uslug@workspace:packages/fork-uslug":
"@joplin/fork-uslug@^1.0.14, @joplin/fork-uslug@workspace:packages/fork-uslug":
version: 0.0.0-use.local
resolution: "@joplin/fork-uslug@workspace:packages/fork-uslug"
dependencies:
@@ -6477,11 +6484,11 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/htmlpack@^2.13.4, @joplin/htmlpack@workspace:packages/htmlpack":
"@joplin/htmlpack@^2.13.3, @joplin/htmlpack@workspace:packages/htmlpack":
version: 0.0.0-use.local
resolution: "@joplin/htmlpack@workspace:packages/htmlpack"
dependencies:
"@joplin/fork-htmlparser2": ^4.1.50
"@joplin/fork-htmlparser2": ^4.1.49
"@types/fs-extra": 11.0.3
css: 3.0.0
datauri: 4.1.0
@@ -6490,27 +6497,27 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/lib@^2.13.4, @joplin/lib@workspace:packages/lib, @joplin/lib@~2.13":
"@joplin/lib@^2.13.3, @joplin/lib@workspace:packages/lib, @joplin/lib@~2.13":
version: 0.0.0-use.local
resolution: "@joplin/lib@workspace:packages/lib"
dependencies:
"@aws-sdk/client-s3": 3.296.0
"@aws-sdk/s3-request-presigner": 3.296.0
"@joplin/fork-htmlparser2": ^4.1.50
"@joplin/fork-sax": ^1.2.54
"@joplin/fork-uslug": ^1.0.15
"@joplin/htmlpack": ^2.13.4
"@joplin/renderer": ^2.13.4
"@joplin/turndown": ^4.0.72
"@joplin/turndown-plugin-gfm": ^1.0.54
"@joplin/utils": ^2.13.4
"@joplin/fork-htmlparser2": ^4.1.49
"@joplin/fork-sax": ^1.2.53
"@joplin/fork-uslug": ^1.0.14
"@joplin/htmlpack": ^2.13.3
"@joplin/renderer": ^2.13.3
"@joplin/turndown": ^4.0.71
"@joplin/turndown-plugin-gfm": ^1.0.53
"@joplin/utils": ^2.13.3
"@types/fs-extra": 11.0.3
"@types/jest": 29.5.5
"@types/js-yaml": 4.0.8
"@types/nanoid": 3.0.0
"@types/node": 18.18.7
"@types/node": 18.18.8
"@types/node-rsa": 1.1.3
"@types/react": 18.2.33
"@types/react": 18.2.34
"@types/uuid": 9.0.6
async-mutex: 0.4.0
base-64: 1.0.0
@@ -6582,7 +6589,7 @@ __metadata:
"@joplin/lib": ~2.13
"@types/jest": 29.5.5
"@types/pdfjs-dist": 2.10.378
"@types/react": 18.2.33
"@types/react": 18.2.34
"@types/react-dom": 18.2.14
"@types/styled-components": 5.1.29
async-mutex: 0.4.0
@@ -6596,7 +6603,7 @@ __metadata:
style-loader: 3.3.3
styled-components: 5.3.11
ts-jest: 29.1.1
ts-loader: 9.4.4
ts-loader: 9.5.0
typescript: 5.2.2
webpack: 5.74.0
webpack-cli: 4.10.0
@@ -6607,12 +6614,12 @@ __metadata:
version: 0.0.0-use.local
resolution: "@joplin/plugin-repo-cli@workspace:packages/plugin-repo-cli"
dependencies:
"@joplin/lib": ^2.13.4
"@joplin/tools": ^2.13.4
"@joplin/utils": ^2.13.4
"@joplin/lib": ^2.13.3
"@joplin/tools": ^2.13.3
"@joplin/utils": ^2.13.3
"@types/fs-extra": 11.0.3
"@types/jest": 29.5.5
"@types/node": 18.18.7
"@types/node": 18.18.8
fs-extra: 11.1.1
gh-release-assets: 2.0.1
jest: 29.7.0
@@ -6658,19 +6665,19 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/renderer@^2.13.4, @joplin/renderer@workspace:packages/renderer, @joplin/renderer@~2.13":
"@joplin/renderer@^2.13.3, @joplin/renderer@workspace:packages/renderer, @joplin/renderer@~2.13":
version: 0.0.0-use.local
resolution: "@joplin/renderer@workspace:packages/renderer"
dependencies:
"@joplin/fork-htmlparser2": ^4.1.50
"@joplin/fork-uslug": ^1.0.15
"@joplin/utils": ^2.13.4
"@joplin/fork-htmlparser2": ^4.1.49
"@joplin/fork-uslug": ^1.0.14
"@joplin/utils": ^2.13.3
"@types/jest": 29.5.5
"@types/markdown-it": 13.0.5
"@types/node": 18.18.7
"@types/node": 18.18.8
font-awesome-filetypes: 2.1.0
fs-extra: 11.1.1
highlight.js: 11.8.0
highlight.js: 11.9.0
html-entities: 1.4.0
jest: 29.7.0
jest-environment-jsdom: 29.7.0
@@ -6736,7 +6743,7 @@ __metadata:
jsdom: 22.1.0
knex: 2.5.1
koa: 2.14.2
ldapts: 7.0.5
ldapts: 7.0.6
markdown-it: 13.0.2
mustache: 4.2.0
nanoid: 2.1.11
@@ -6749,7 +6756,7 @@ __metadata:
pretty-bytes: 5.6.0
prettycron: 0.10.0
query-string: 7.1.3
rate-limiter-flexible: 2.4.2
rate-limiter-flexible: 3.0.3
raw-body: 2.5.2
source-map-support: 0.5.21
sqlite3: 5.1.6
@@ -6761,23 +6768,23 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/tools@^2.13.4, @joplin/tools@workspace:packages/tools, @joplin/tools@~2.13":
"@joplin/tools@^2.13.3, @joplin/tools@workspace:packages/tools, @joplin/tools@~2.13":
version: 0.0.0-use.local
resolution: "@joplin/tools@workspace:packages/tools"
dependencies:
"@docusaurus/plugin-sitemap": 2.4.3
"@joplin/fork-htmlparser2": ^4.1.50
"@joplin/lib": ^2.13.4
"@joplin/renderer": ^2.13.4
"@joplin/utils": ^2.13.4
"@joplin/fork-htmlparser2": ^4.1.49
"@joplin/lib": ^2.13.3
"@joplin/renderer": ^2.13.3
"@joplin/utils": ^2.13.3
"@rmp135/sql-ts": 1.18.0
"@types/fs-extra": 11.0.3
"@types/jest": 29.5.5
"@types/js-yaml": 4.0.8
"@types/markdown-it": 13.0.5
"@types/mustache": 4.2.4
"@types/node": 18.18.7
"@types/node-fetch": 2.6.7
"@types/node": 18.18.8
"@types/node-fetch": 2.6.8
"@types/yargs": 17.0.29
compare-versions: 6.1.0
dayjs: 1.11.10
@@ -6802,14 +6809,14 @@ __metadata:
sharp: 0.32.6
source-map-support: 0.5.21
sqlite3: 5.1.6
style-to-js: 1.1.8
style-to-js: 1.1.9
typescript: 5.2.2
uri-template: 2.0.0
yargs: 17.7.2
languageName: unknown
linkType: soft
"@joplin/turndown-plugin-gfm@^1.0.54, @joplin/turndown-plugin-gfm@workspace:packages/turndown-plugin-gfm":
"@joplin/turndown-plugin-gfm@^1.0.53, @joplin/turndown-plugin-gfm@workspace:packages/turndown-plugin-gfm":
version: 0.0.0-use.local
resolution: "@joplin/turndown-plugin-gfm@workspace:packages/turndown-plugin-gfm"
dependencies:
@@ -6821,7 +6828,7 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/turndown@^4.0.72, @joplin/turndown@workspace:packages/turndown":
"@joplin/turndown@^4.0.71, @joplin/turndown@workspace:packages/turndown":
version: 0.0.0-use.local
resolution: "@joplin/turndown@workspace:packages/turndown"
dependencies:
@@ -6838,13 +6845,13 @@ __metadata:
languageName: unknown
linkType: soft
"@joplin/utils@^2.13.4, @joplin/utils@workspace:packages/utils, @joplin/utils@~2.13":
"@joplin/utils@^2.13.3, @joplin/utils@workspace:packages/utils, @joplin/utils@~2.13":
version: 0.0.0-use.local
resolution: "@joplin/utils@workspace:packages/utils"
dependencies:
"@types/fs-extra": 11.0.3
"@types/jest": 29.5.5
"@types/node-fetch": 2.6.7
"@types/node-fetch": 2.6.8
async-mutex: 0.4.0
execa: 5.1.1
fs-extra: 11.1.1
@@ -6990,12 +6997,12 @@ __metadata:
languageName: node
linkType: hard
"@js-draw/material-icons@npm:1.14.0":
version: 1.14.0
resolution: "@js-draw/material-icons@npm:1.14.0"
"@js-draw/material-icons@npm:1.11.2":
version: 1.11.2
resolution: "@js-draw/material-icons@npm:1.11.2"
peerDependencies:
js-draw: ^1.0.1
checksum: 6e67ee6399b9b4f9e5891952e71a978acd69c0d386fe80c957ad884ab8e9f4f954aa0d9dd1b08e78f314b0b8f3807989a482ed4a153457a8bba67f5989dd7a0c
checksum: 6a6bbdf936d3a97fab43321d807672f157b12201290a98bd3fd33a7e53966647ed9c5a8aba5dfd6d743bfc37ab9ddff14cbb7fc3f4ffb8b79ff7617a7e886160
languageName: node
linkType: hard
@@ -8095,6 +8102,16 @@ __metadata:
languageName: node
linkType: hard
"@npmcli/fs@npm:^2.1.0":
version: 2.1.2
resolution: "@npmcli/fs@npm:2.1.2"
dependencies:
"@gar/promisify": ^1.1.3
semver: ^7.3.5
checksum: 405074965e72d4c9d728931b64d2d38e6ea12066d4fad651ac253d175e413c06fe4350970c783db0d749181da8fe49c42d3880bd1cbc12cd68e3a7964d820225
languageName: node
linkType: hard
"@npmcli/fs@npm:^3.1.0":
version: 3.1.0
resolution: "@npmcli/fs@npm:3.1.0"
@@ -8142,6 +8159,16 @@ __metadata:
languageName: node
linkType: hard
"@npmcli/move-file@npm:^2.0.0":
version: 2.0.1
resolution: "@npmcli/move-file@npm:2.0.1"
dependencies:
mkdirp: ^1.0.4
rimraf: ^3.0.2
checksum: 52dc02259d98da517fae4cb3a0a3850227bdae4939dda1980b788a7670636ca2b4a01b58df03dd5f65c1e3cb70c50fa8ce5762b582b3f499ec30ee5ce1fd9380
languageName: node
linkType: hard
"@npmcli/node-gyp@npm:^3.0.0":
version: 3.0.0
resolution: "@npmcli/node-gyp@npm:3.0.0"
@@ -8459,14 +8486,14 @@ __metadata:
languageName: node
linkType: hard
"@playwright/test@npm:1.38.1":
version: 1.38.1
resolution: "@playwright/test@npm:1.38.1"
"@playwright/test@npm:1.39.0":
version: 1.39.0
resolution: "@playwright/test@npm:1.39.0"
dependencies:
playwright: 1.38.1
playwright: 1.39.0
bin:
playwright: cli.js
checksum: c5ec0b23261fe1ef163b6234f69263bc10e7e5a3fb676c7773ffc70b87459a7ab225f57c03b9de649475771638a04c2e00d9b2739304a4dcf5d3edf20a7a4a82
checksum: e93e58fc1af4239f239b890374f066c9a758e2492d25e2c1a532f3f00782ab8e7706956a07540fd14882c74e75f5de36273621adce9b79afb8e36e6c15f1d539
languageName: node
linkType: hard
@@ -8949,12 +8976,12 @@ __metadata:
languageName: node
linkType: hard
"@react-native-community/netinfo@npm:9.4.1":
version: 9.4.1
resolution: "@react-native-community/netinfo@npm:9.4.1"
"@react-native-community/netinfo@npm:9.4.2":
version: 9.4.2
resolution: "@react-native-community/netinfo@npm:9.4.2"
peerDependencies:
react-native: ">=0.59"
checksum: cf6471a50a5282f858797cda7531c61ac3d94de2e1c379b14a11f6b049f582606dae55a041dd900c56b01faf69eb5cfef9b4e84b0ea7f02de52804aa5a6e22df
checksum: b7783d615dec52e89dfd5f435101c06a1b17b11d6702685ad0ad73fb5c9d3ab6997e7a640b7f0f1f5bb068135331adfb5fb77280ec7b3a19e4332f50f055efd8
languageName: node
linkType: hard
@@ -9662,9 +9689,9 @@ __metadata:
languageName: node
linkType: hard
"@testing-library/react-native@npm:12.3.1":
version: 12.3.1
resolution: "@testing-library/react-native@npm:12.3.1"
"@testing-library/react-native@npm:12.3.2":
version: 12.3.2
resolution: "@testing-library/react-native@npm:12.3.2"
dependencies:
jest-matcher-utils: ^29.7.0
pretty-format: ^29.7.0
@@ -9677,7 +9704,7 @@ __metadata:
peerDependenciesMeta:
jest:
optional: true
checksum: ad50508e35b077533d5a711c01d96758a82da6bca255bc37f0c9f037c44cde67efbd5984862aec8cb7c4c0c8648b21f3f09378b2fe9e067aa593e5fcb49038e7
checksum: c6fdaf64865a079b885ff83ae172330b354dbd13cb9a4370578a544080d87f21cc7a93e079a3bc4256ab0893c5de36feae4bcf6edf24b3a6617019f4369a6053
languageName: node
linkType: hard
@@ -9770,12 +9797,12 @@ __metadata:
languageName: node
linkType: hard
"@types/asn1@npm:>=0.2.1":
version: 0.2.2
resolution: "@types/asn1@npm:0.2.2"
"@types/asn1@npm:>=0.2.2":
version: 0.2.3
resolution: "@types/asn1@npm:0.2.3"
dependencies:
"@types/node": "*"
checksum: cd64dab0a214a88360995adf86f307565bf13f14d27552590cbb8cefea30585d65385be831b644fee790654bf7d29eae6ed07ba1db0bed59075aac4fb0b8b63d
checksum: c5debd9088d664e71d87816d15a3dcd1d200ffd36b22fc82d0a0f53fba4b7a35f83e1ad1142abfb8052e47a9e516e14d4256341a11415f8b67cfb032f01a08a1
languageName: node
linkType: hard
@@ -10413,13 +10440,13 @@ __metadata:
languageName: node
linkType: hard
"@types/node-fetch@npm:2.6.7":
version: 2.6.7
resolution: "@types/node-fetch@npm:2.6.7"
"@types/node-fetch@npm:2.6.8":
version: 2.6.8
resolution: "@types/node-fetch@npm:2.6.8"
dependencies:
"@types/node": "*"
form-data: ^4.0.0
checksum: 543a540186941e81ca4dda283b5f7bce1d7a93af3ee2c8161fc48d078789e9ce976332ce70f22644293414f680e3f9627d3ef8f59105cf2ea901d5e4acf58d3f
checksum: f40e5e2fa3ca05a45453397e891776619739f093f913199c00c141735f8098e4f2ffdea04b9d608182aede2df9607605c71e0fdb97d2614899545ce81bac7005
languageName: node
linkType: hard
@@ -10439,21 +10466,12 @@ __metadata:
languageName: node
linkType: hard
"@types/node@npm:18.18.7":
version: 18.18.7
resolution: "@types/node@npm:18.18.7"
"@types/node@npm:18.18.8":
version: 18.18.8
resolution: "@types/node@npm:18.18.8"
dependencies:
undici-types: ~5.26.4
checksum: 972f8b214f961b6c8d99f84aab8bfadc656bb71fc7ad4a543ad3405286c95f27385ee0c3844f88d612f3cf225cd4d49ce8a7d9aea05a2aba9b2524ac525040aa
languageName: node
linkType: hard
"@types/node@npm:>=18":
version: 20.8.9
resolution: "@types/node@npm:20.8.9"
dependencies:
undici-types: ~5.26.4
checksum: 0c05f3502a9507ff27e91dd6fd574fa6f391b3fafedcfe8e0c8d33351fb22d02c0121f854e5b6b3ecb9a8a468407ddf6e7ac0029fb236d4c7e1361ffc758a01f
checksum: d6a82bfc28bca8e4e32ffc9526798d1aea62f6993ea3a535cd3f47ac3f725a48efe3f484d68168dd154af0001c89935e4e1d77e7b1809c3824c6382bf99b86f6
languageName: node
linkType: hard
@@ -10641,14 +10659,14 @@ __metadata:
languageName: node
linkType: hard
"@types/react@npm:18.2.33":
version: 18.2.33
resolution: "@types/react@npm:18.2.33"
"@types/react@npm:18.2.34":
version: 18.2.34
resolution: "@types/react@npm:18.2.34"
dependencies:
"@types/prop-types": "*"
"@types/scheduler": "*"
csstype: ^3.0.2
checksum: 75903c4d53898c69dd23d0b2730eac4676dc5ade15c25c793dec855f0d7c650cb823832bb1dd881efe8895724f15b06d4bf7081ea0b82391aa3059512ad49ccf
checksum: 16446542228cba827143caf0ecb4718cbf02ae5befd4a6bc6d67ed144fe1c0cb4b06b20facf3d2b972d86c67a17cc82f5ec8a03fce42d50e12b2dcd0592fc66e
languageName: node
linkType: hard
@@ -14370,6 +14388,32 @@ __metadata:
languageName: node
linkType: hard
"cacache@npm:^16.1.0":
version: 16.1.3
resolution: "cacache@npm:16.1.3"
dependencies:
"@npmcli/fs": ^2.1.0
"@npmcli/move-file": ^2.0.0
chownr: ^2.0.0
fs-minipass: ^2.1.0
glob: ^8.0.1
infer-owner: ^1.0.4
lru-cache: ^7.7.1
minipass: ^3.1.6
minipass-collect: ^1.0.2
minipass-flush: ^1.0.5
minipass-pipeline: ^1.2.4
mkdirp: ^1.0.4
p-map: ^4.0.0
promise-inflight: ^1.0.1
rimraf: ^3.0.2
ssri: ^9.0.0
tar: ^6.1.11
unique-filename: ^2.0.0
checksum: d91409e6e57d7d9a3a25e5dcc589c84e75b178ae8ea7de05cbf6b783f77a5fae938f6e8fda6f5257ed70000be27a681e1e44829251bfffe4c10216002f8f14e6
languageName: node
linkType: hard
"cacache@npm:^17.0.0":
version: 17.1.3
resolution: "cacache@npm:17.1.3"
@@ -21533,7 +21577,7 @@ __metadata:
languageName: node
linkType: hard
"fs-minipass@npm:^2.0.0":
"fs-minipass@npm:^2.0.0, fs-minipass@npm:^2.1.0":
version: 2.1.0
resolution: "fs-minipass@npm:2.1.0"
dependencies:
@@ -22287,6 +22331,19 @@ __metadata:
languageName: node
linkType: hard
"glob@npm:^8.0.1":
version: 8.1.0
resolution: "glob@npm:8.1.0"
dependencies:
fs.realpath: ^1.0.0
inflight: ^1.0.4
inherits: 2
minimatch: ^5.0.1
once: ^1.3.0
checksum: 92fbea3221a7d12075f26f0227abac435de868dd0736a17170663783296d0dd8d3d532a5672b4488a439bf5d7fb85cdd07c11185d6cd39184f0385cbdfb86a47
languageName: node
linkType: hard
"glob@npm:^8.0.3":
version: 8.0.3
resolution: "glob@npm:8.0.3"
@@ -23072,10 +23129,10 @@ __metadata:
languageName: node
linkType: hard
"highlight.js@npm:11.8.0":
version: 11.8.0
resolution: "highlight.js@npm:11.8.0"
checksum: d2578a57aee7315946ff19379053fd0a28b127baabf7617ab1d28d62cdc4eaf3d75053569cb8479a5afdc7a68f1ba9a6c1d612d8ae399b4b9aa43093b4fb6831
"highlight.js@npm:11.9.0":
version: 11.9.0
resolution: "highlight.js@npm:11.9.0"
checksum: 4043d31c5de9d27d13387d9a9e5e1939557254b7b85f0fab85d9cae0e420e131a3456ebf6148552020a1d8a216d671d583f2433d6c4de6179b8a66487a8325cb
languageName: node
linkType: hard
@@ -26239,7 +26296,7 @@ __metadata:
"@joplin/utils": ~2.13
"@types/fs-extra": 11.0.3
"@types/jest": 29.5.5
"@types/node": 18.18.7
"@types/node": 18.18.8
"@types/proper-lockfile": ^4.1.2
aws-sdk: 2.1340.0
chalk: 4.1.2
@@ -26295,13 +26352,13 @@ __metadata:
languageName: node
linkType: hard
"js-draw@npm:1.14.0":
version: 1.14.0
resolution: "js-draw@npm:1.14.0"
"js-draw@npm:1.11.2":
version: 1.11.2
resolution: "js-draw@npm:1.11.2"
dependencies:
"@js-draw/math": ^1.11.1
"@melloware/coloris": 0.22.0
checksum: 0e2bbf318a8ebc645ed83f8cf0ef1f43a49d85b5f83e0be1616ec200d37817070a002bda54ef21df72d74a37597aa61e61e94559b27fbe4de8fcdb70effa04d4
checksum: 59669bbe37f4c980f8532b96ec7a80880966beca3a82973fa0681c3988d8ed12745d5c1b27645853806087664c14fa49530fc8815a471346f03b3ef7c4366ea9
languageName: node
linkType: hard
@@ -27161,18 +27218,17 @@ __metadata:
languageName: node
linkType: hard
"ldapts@npm:7.0.5":
version: 7.0.5
resolution: "ldapts@npm:7.0.5"
"ldapts@npm:7.0.6":
version: 7.0.6
resolution: "ldapts@npm:7.0.6"
dependencies:
"@types/asn1": ">=0.2.1"
"@types/node": ">=18"
"@types/asn1": ">=0.2.2"
"@types/uuid": ">=9"
asn1: ~0.2.6
debug: ~4.3.4
strict-event-emitter-types: ~2.0.0
uuid: ~9.0.1
checksum: 063a84b6ed2ce55f1eeff374da0a5b7f12431e2c54e03bcb35fe1a5eecb6bdf6e95130b80ab28ea6b36db09a442e3e07c4e04e9bb827276e1cc1f5269597a828
checksum: 43ca9b4924459154b3692147dbe140274e164c1dc34a31692c23b742541a97ba0fe42a52193854ee0aa6f5fd9dcdaa70bc39fc16a617768ea1a260fa2ff49cb3
languageName: node
linkType: hard
@@ -27957,6 +28013,30 @@ __metadata:
languageName: node
linkType: hard
"make-fetch-happen@npm:^10.0.3":
version: 10.2.1
resolution: "make-fetch-happen@npm:10.2.1"
dependencies:
agentkeepalive: ^4.2.1
cacache: ^16.1.0
http-cache-semantics: ^4.1.0
http-proxy-agent: ^5.0.0
https-proxy-agent: ^5.0.0
is-lambda: ^1.0.1
lru-cache: ^7.7.1
minipass: ^3.1.6
minipass-collect: ^1.0.2
minipass-fetch: ^2.0.3
minipass-flush: ^1.0.5
minipass-pipeline: ^1.2.4
negotiator: ^0.6.3
promise-retry: ^2.0.1
socks-proxy-agent: ^7.0.0
ssri: ^9.0.0
checksum: 2332eb9a8ec96f1ffeeea56ccefabcb4193693597b132cd110734d50f2928842e22b84cfa1508e921b8385cdfd06dda9ad68645fed62b50fff629a580f5fb72c
languageName: node
linkType: hard
"make-fetch-happen@npm:^11.0.0, make-fetch-happen@npm:^11.0.1, make-fetch-happen@npm:^11.0.3, make-fetch-happen@npm:^11.1.1":
version: 11.1.1
resolution: "make-fetch-happen@npm:11.1.1"
@@ -29737,6 +29817,21 @@ __metadata:
languageName: node
linkType: hard
"minipass-fetch@npm:^2.0.3":
version: 2.1.2
resolution: "minipass-fetch@npm:2.1.2"
dependencies:
encoding: ^0.1.13
minipass: ^3.1.6
minipass-sized: ^1.0.3
minizlib: ^2.1.2
dependenciesMeta:
encoding:
optional: true
checksum: 3f216be79164e915fc91210cea1850e488793c740534985da017a4cbc7a5ff50506956d0f73bb0cb60e4fe91be08b6b61ef35101706d3ef5da2c8709b5f08f91
languageName: node
linkType: hard
"minipass-fetch@npm:^3.0.0":
version: 3.0.3
resolution: "minipass-fetch@npm:3.0.3"
@@ -30548,7 +30643,28 @@ __metadata:
languageName: node
linkType: hard
"node-gyp@npm:9.4.0, node-gyp@npm:^9.0.0, node-gyp@npm:latest":
"node-gyp@npm:9.4.1":
version: 9.4.1
resolution: "node-gyp@npm:9.4.1"
dependencies:
env-paths: ^2.2.0
exponential-backoff: ^3.1.1
glob: ^7.1.4
graceful-fs: ^4.2.6
make-fetch-happen: ^10.0.3
nopt: ^6.0.0
npmlog: ^6.0.0
rimraf: ^3.0.2
semver: ^7.3.5
tar: ^6.1.2
which: ^2.0.2
bin:
node-gyp: bin/node-gyp.js
checksum: 8576c439e9e925ab50679f87b7dfa7aa6739e42822e2ad4e26c36341c0ba7163fdf5a946f0a67a476d2f24662bc40d6c97bd9e79ced4321506738e6b760a1577
languageName: node
linkType: hard
"node-gyp@npm:^9.0.0, node-gyp@npm:latest":
version: 9.4.0
resolution: "node-gyp@npm:9.4.0"
dependencies:
@@ -32744,27 +32860,27 @@ __metadata:
languageName: node
linkType: hard
"playwright-core@npm:1.38.1":
version: 1.38.1
resolution: "playwright-core@npm:1.38.1"
"playwright-core@npm:1.39.0":
version: 1.39.0
resolution: "playwright-core@npm:1.39.0"
bin:
playwright-core: cli.js
checksum: 66e83fe040f309b13ad94ba39dea40ac207bfcbbc22de13141af88dbdedd64e1c4e3ce1d0cb070d4efd8050d7e579953ec3681dd8a0acf2c1cc738d9c50e545e
checksum: 556e78dee4f9890facf2af8249972e0d6e01a5ae98737b0f6b0166c660a95ffee4cb79350335b1ef96430a0ef01d3669daae9099fa46c8d403d11c623988238b
languageName: node
linkType: hard
"playwright@npm:1.38.1":
version: 1.38.1
resolution: "playwright@npm:1.38.1"
"playwright@npm:1.39.0":
version: 1.39.0
resolution: "playwright@npm:1.39.0"
dependencies:
fsevents: 2.3.2
playwright-core: 1.38.1
playwright-core: 1.39.0
dependenciesMeta:
fsevents:
optional: true
bin:
playwright: cli.js
checksum: 4e01d4ee52d9ccf75a80d8492829106802590721d56bff7c5957ff1f21eb3c328ee5bc3c1784a59c4b515df1b98d08ef92e4a35a807f454cd00dc481d30fadc2
checksum: 96d8ca5aa25465c1c5d554d0d6071981d55e22477800ff8f5d47a53ca75193d60ece2df538a01b7165b3277dd5493c67603a5acda713029df7fbd95ce2417bc9
languageName: node
linkType: hard
@@ -34026,10 +34142,10 @@ __metadata:
languageName: node
linkType: hard
"punycode@npm:2.3.0, punycode@npm:^2.3.0":
version: 2.3.0
resolution: "punycode@npm:2.3.0"
checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200
"punycode@npm:2.3.1":
version: 2.3.1
resolution: "punycode@npm:2.3.1"
checksum: bb0a0ceedca4c3c57a9b981b90601579058903c62be23c5e8e843d2c2d4148a3ecf029d5133486fb0e1822b098ba8bba09e89d6b21742d02fa26bda6441a6fb2
languageName: node
linkType: hard
@@ -34047,6 +34163,13 @@ __metadata:
languageName: node
linkType: hard
"punycode@npm:^2.3.0":
version: 2.3.0
resolution: "punycode@npm:2.3.0"
checksum: 39f760e09a2a3bbfe8f5287cf733ecdad69d6af2fe6f97ca95f24b8921858b91e9ea3c9eeec6e08cede96181b3bb33f95c6ffd8c77e63986508aa2e8159fa200
languageName: node
linkType: hard
"pupa@npm:^2.1.1":
version: 2.1.1
resolution: "pupa@npm:2.1.1"
@@ -34256,10 +34379,10 @@ __metadata:
languageName: node
linkType: hard
"rate-limiter-flexible@npm:2.4.2":
version: 2.4.2
resolution: "rate-limiter-flexible@npm:2.4.2"
checksum: 039e58b664991963ba2668a83d0406a72e5822683103acbe416854deb92ed834b840ce6e0acfea35917d9b49685bd53946ae47435a9f5916c2e7550395dec9dc
"rate-limiter-flexible@npm:3.0.3":
version: 3.0.3
resolution: "rate-limiter-flexible@npm:3.0.3"
checksum: 3854577d78511e225028ec592987a64d2daab3235e159ce64bf875eb47090f8c01073d8095283cff2a253708b0a81c7a413844f8f8077af8528716fb1b44a50f
languageName: node
linkType: hard
@@ -36581,7 +36704,7 @@ __metadata:
lerna: 3.22.1
lint-staged: 14.0.1
madge: 6.1.0
node-gyp: 9.4.0
node-gyp: 9.4.1
nodemon: 3.0.1
npm-package-json-lint: 7.0.0
typescript: 5.2.2
@@ -37967,6 +38090,13 @@ __metadata:
languageName: node
linkType: hard
"source-map@npm:^0.7.4":
version: 0.7.4
resolution: "source-map@npm:0.7.4"
checksum: 01cc5a74b1f0e1d626a58d36ad6898ea820567e87f18dfc9d24a9843a351aaa2ec09b87422589906d6ff1deed29693e176194dc88bcae7c9a852dc74b311dbf5
languageName: node
linkType: hard
"space-separated-tokens@npm:^1.0.0":
version: 1.1.5
resolution: "space-separated-tokens@npm:1.1.5"
@@ -38209,6 +38339,15 @@ __metadata:
languageName: node
linkType: hard
"ssri@npm:^9.0.0":
version: 9.0.1
resolution: "ssri@npm:9.0.1"
dependencies:
minipass: ^3.1.1
checksum: fb58f5e46b6923ae67b87ad5ef1c5ab6d427a17db0bead84570c2df3cd50b4ceb880ebdba2d60726588272890bae842a744e1ecce5bd2a2a582fccd5068309eb
languageName: node
linkType: hard
"stable@npm:^0.1.8":
version: 0.1.8
resolution: "stable@npm:0.1.8"
@@ -38909,12 +39048,12 @@ __metadata:
languageName: node
linkType: hard
"style-to-js@npm:1.1.8":
version: 1.1.8
resolution: "style-to-js@npm:1.1.8"
"style-to-js@npm:1.1.9":
version: 1.1.9
resolution: "style-to-js@npm:1.1.9"
dependencies:
style-to-object: 1.0.3
checksum: cc4d4284af587bf74559a6da17dadb88c96c8054755666cce1b768615ac2bd6231ce332a8cee118acafb577f51f243b795b716326b3c617ec12151d23f660d8f
style-to-object: 1.0.4
checksum: f05dcd9edc7c2b530159c3eea7be558ebd324073dad444220ca3c12a15bdfa55f5690625238597190d0e21cc87433d6b745eb757055e0e781998153863fdc105
languageName: node
linkType: hard
@@ -38927,12 +39066,12 @@ __metadata:
languageName: node
linkType: hard
"style-to-object@npm:1.0.3":
version: 1.0.3
resolution: "style-to-object@npm:1.0.3"
"style-to-object@npm:1.0.4":
version: 1.0.4
resolution: "style-to-object@npm:1.0.4"
dependencies:
inline-style-parser: 0.2.2
checksum: fca6b35dc704656163c4b11d514ada9f9998fb434c9cec5995445d7d7d595ba3a4fda0476016d625cbb282d43ba5123ef0b5871d855d391400bb0dc2c2beeae1
checksum: d3d2ea838b7777d3d6db165df8322e0f6b4f550f081e5833c89c4d91e5de2f7a09fa81cfd2208221683a94e476d4fc24df65c4d3ab75ddd45b419bef9426fbaf
languageName: node
linkType: hard
@@ -40238,18 +40377,19 @@ __metadata:
languageName: node
linkType: hard
"ts-loader@npm:9.4.4":
version: 9.4.4
resolution: "ts-loader@npm:9.4.4"
"ts-loader@npm:9.5.0":
version: 9.5.0
resolution: "ts-loader@npm:9.5.0"
dependencies:
chalk: ^4.1.0
enhanced-resolve: ^5.0.0
micromatch: ^4.0.0
semver: ^7.3.4
source-map: ^0.7.4
peerDependencies:
typescript: "*"
webpack: ^5.0.0
checksum: 8e5e6b839b0edfa40d2156c880d88ccab58226894ea5978221bc48c7db3215e2e856bfd0093f148e925a2befc42d6c94cafa9a994a7da274541efaa916012b63
checksum: a319575faa07145917a7050ac6be7e7f8d97745c6b6ecf8097ac51cebd2d459e8f8b2519d0c39066a065f4d73ae331d2aba9de3d62ea38bc59fd84395794d428
languageName: node
linkType: hard
@@ -41082,6 +41222,15 @@ __metadata:
languageName: node
linkType: hard
"unique-filename@npm:^2.0.0":
version: 2.0.1
resolution: "unique-filename@npm:2.0.1"
dependencies:
unique-slug: ^3.0.0
checksum: 807acf3381aff319086b64dc7125a9a37c09c44af7620bd4f7f3247fcd5565660ac12d8b80534dcbfd067e6fe88a67e621386dd796a8af828d1337a8420a255f
languageName: node
linkType: hard
"unique-filename@npm:^3.0.0":
version: 3.0.0
resolution: "unique-filename@npm:3.0.0"
@@ -41100,6 +41249,15 @@ __metadata:
languageName: node
linkType: hard
"unique-slug@npm:^3.0.0":
version: 3.0.0
resolution: "unique-slug@npm:3.0.0"
dependencies:
imurmurhash: ^0.1.4
checksum: 49f8d915ba7f0101801b922062ee46b7953256c93ceca74303bd8e6413ae10aa7e8216556b54dc5382895e8221d04f1efaf75f945c2e4a515b4139f77aa6640c
languageName: node
linkType: hard
"unique-slug@npm:^4.0.0":
version: 4.0.0
resolution: "unique-slug@npm:4.0.0"