You've already forked joplin
mirror of
https://github.com/laurent22/joplin.git
synced 2025-08-24 20:19:10 +02:00
Compare commits
131 Commits
cli-v1.0.1
...
v1.0.187
Author | SHA1 | Date | |
---|---|---|---|
|
c2049b21fc | ||
|
a415b9d7ae | ||
|
cb4fd1ebf9 | ||
|
a28b790256 | ||
|
55847fa22f | ||
|
6ca0e6adcc | ||
|
6542a60d61 | ||
|
ef4e1c53b7 | ||
|
ec64bf2f0f | ||
|
54dc2219fe | ||
|
a576ad2a39 | ||
|
25a246b6ae | ||
|
4840671f0e | ||
|
1d284a3528 | ||
|
721dd17686 | ||
|
3830f5ee46 | ||
|
ef8af13500 | ||
|
16fb1bda53 | ||
|
e8fcb0cc87 | ||
|
0e23ea5284 | ||
|
f9143ad817 | ||
|
925c03acca | ||
|
421d7a947f | ||
|
7104d5b480 | ||
|
ddb631d800 | ||
|
6107af625f | ||
|
2ce40e0390 | ||
|
3f267f3774 | ||
|
91ef985353 | ||
|
cc759afe16 | ||
|
fd405457e4 | ||
|
65706980a2 | ||
|
04851284ca | ||
|
fbedc6b29b | ||
|
d228ff9fbd | ||
|
0f28060795 | ||
|
1df8509e4d | ||
|
1229b772fe | ||
|
3cf3cd1598 | ||
|
c5f1f11f2d | ||
|
b4b424bf8a | ||
|
2d1aa27955 | ||
|
1f803662d3 | ||
|
2cbbc7100a | ||
|
ed2a6f15fd | ||
|
1aa806df85 | ||
|
17aa5ae243 | ||
|
1a96ee4c6b | ||
|
0d9ff26d51 | ||
|
ce40813bcf | ||
|
ea1db84fcc | ||
|
c79ee74b4c | ||
|
3407a31cf6 | ||
|
2dfe693564 | ||
|
e99edd4af9 | ||
|
8d43e1215a | ||
|
6449289147 | ||
|
5a33dcaf07 | ||
|
2e804086eb | ||
|
5bbedc7e3c | ||
|
9455936f19 | ||
|
9af4ec7b04 | ||
|
fb619a0099 | ||
|
35e369ff1a | ||
|
2fa8e2ff09 | ||
|
eeb9999334 | ||
|
e6cbd8c8f8 | ||
|
5a40204cb3 | ||
|
805cf06af7 | ||
|
bdce832fee | ||
|
4c97aa8542 | ||
|
ca9102d4f5 | ||
|
4f8e7b0e2b | ||
|
9e92c9230b | ||
|
2fef4a0c09 | ||
|
00dc711ffa | ||
|
a52c261d95 | ||
|
c63d8a70b8 | ||
|
79f5bcd2fc | ||
|
675ef8aefd | ||
|
f97bae0b27 | ||
|
3361901cd8 | ||
|
3db47b575b | ||
|
b1ab59b2e6 | ||
|
652b852f6d | ||
|
54fd2049a8 | ||
|
06d807d9ff | ||
|
b66b1ba9e6 | ||
|
06f71cea24 | ||
|
88eed12c78 | ||
|
ea75f65e35 | ||
|
b1a9b448a6 | ||
|
c27c3c48ba | ||
|
fdf28c3513 | ||
|
018222a1f4 | ||
|
ca5d6c5cfe | ||
|
d02488f00c | ||
|
1d14c8a706 | ||
|
573b744293 | ||
|
4bd326f72c | ||
|
d278809659 | ||
|
8053e11b9a | ||
|
5f544fba8a | ||
|
8ee0d8a73e | ||
|
b56352cb4e | ||
|
6d0cc97635 | ||
|
384c7cd831 | ||
|
9ec1e84ed0 | ||
|
691521c5b9 | ||
|
a1e77b4ccd | ||
|
f90da61a85 | ||
|
0b0ff15dde | ||
|
9b157c7ac3 | ||
|
525ba12fc8 | ||
|
2785b8ffc5 | ||
|
cd9d5db3c2 | ||
|
d8ef15a1e2 | ||
|
f1015ca73d | ||
|
e865a5d7c6 | ||
|
cd6e5ccfb8 | ||
|
46ca24cf9d | ||
|
813137efc9 | ||
|
4235288c55 | ||
|
7fd445173d | ||
|
1e190bbe70 | ||
|
0229686203 | ||
|
1606076b4e | ||
|
cd630e9516 | ||
|
3b200e5c92 | ||
|
639712c003 | ||
|
cfb59f2f19 |
@@ -6,6 +6,7 @@ _releases/
|
||||
Assets/
|
||||
CliClient/build
|
||||
CliClient/locales
|
||||
CliClient/locales-build
|
||||
CliClient/node_modules
|
||||
CliClient/tests-build
|
||||
CliClient/tests/enex_to_md
|
||||
@@ -14,20 +15,20 @@ CliClient/tests/logs
|
||||
CliClient/tests/support
|
||||
CliClient/tests/sync
|
||||
CliClient/tests/tmp
|
||||
Clipper/joplin-webclipper/content_scripts/JSDOMParser.js
|
||||
Clipper/joplin-webclipper/content_scripts/Readability-readerable.js
|
||||
Clipper/joplin-webclipper/content_scripts/Readability.js
|
||||
Clipper/joplin-webclipper/dist
|
||||
Clipper/joplin-webclipper/icons
|
||||
Clipper/joplin-webclipper/popup/build
|
||||
Clipper/joplin-webclipper/popup/node_modules
|
||||
Clipper/content_scripts/JSDOMParser.js
|
||||
Clipper/content_scripts/Readability-readerable.js
|
||||
Clipper/content_scripts/Readability.js
|
||||
Clipper/dist
|
||||
Clipper/icons
|
||||
Clipper/popup/build
|
||||
Clipper/popup/node_modules
|
||||
docs/
|
||||
ElectronClient/app/dist
|
||||
ElectronClient/app/lib
|
||||
ElectronClient/app/lib/vendor/sjcl-rn.js
|
||||
ElectronClient/app/lib/vendor/sjcl.js
|
||||
ElectronClient/app/locales
|
||||
ElectronClient/app/node_modules
|
||||
ElectronClient/dist
|
||||
ElectronClient/lib
|
||||
ElectronClient/lib/vendor/sjcl-rn.js
|
||||
ElectronClient/lib/vendor/sjcl.js
|
||||
ElectronClient/locales
|
||||
ElectronClient/node_modules
|
||||
highlight.pack.js
|
||||
node_modules/
|
||||
ReactNativeClient/android
|
||||
@@ -45,11 +46,19 @@ Server/docs/
|
||||
Server/dist/
|
||||
Server/bin/
|
||||
Server/node_modules/
|
||||
ElectronClient/app/packageInfo.js
|
||||
ElectronClient/packageInfo.js
|
||||
ReactNativeClient/pluginAssets/
|
||||
ReactNativeClient/lib/joplin-renderer/vendor/fountain.min.js
|
||||
ReactNativeClient/lib/joplin-renderer/assets/
|
||||
ReactNativeClient/lib/rnInjectedJs/
|
||||
|
||||
# Ignore files generated from TypeScript files
|
||||
ElectronClient/app/gui/ShareNoteDialog.js
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
ElectronClient/gui/NoteContentPropertiesDialog.js
|
||||
ElectronClient/gui/ResourceScreen.js
|
||||
ElectronClient/gui/ShareNoteDialog.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
|
||||
ReactNativeClient/lib/JoplinServerApi.js
|
||||
ReactNativeClient/PluginAssetsLoader.js
|
||||
ReactNativeClient/setUpQuickActions.js
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
|
15
.eslintrc.js
15
.eslintrc.js
@@ -19,7 +19,10 @@ module.exports = {
|
||||
'expect': 'readonly',
|
||||
'describe': 'readonly',
|
||||
'it': 'readonly',
|
||||
'beforeAll': 'readonly',
|
||||
'afterAll': 'readonly',
|
||||
'beforeEach': 'readonly',
|
||||
'afterEach': 'readonly',
|
||||
'jasmine': 'readonly',
|
||||
|
||||
// React Native variables
|
||||
@@ -50,10 +53,10 @@ module.exports = {
|
||||
// possible race conditions in contexts where we know it cannot happen.
|
||||
"require-atomic-updates": 0,
|
||||
|
||||
// -------------------------------
|
||||
// Coding style preferences
|
||||
// -------------------------------
|
||||
"enforce-react-hooks/enforce-react-hooks": 2,
|
||||
// Checks rules of Hooks
|
||||
"react-hooks/rules-of-hooks": "error",
|
||||
// Checks effect dependencies
|
||||
"react-hooks/exhaustive-deps": "error",
|
||||
|
||||
// -------------------------------
|
||||
// Formatting
|
||||
@@ -92,6 +95,6 @@ module.exports = {
|
||||
"plugins": [
|
||||
"react",
|
||||
"@typescript-eslint",
|
||||
"enforce-react-hooks",
|
||||
"react-hooks"
|
||||
],
|
||||
};
|
||||
};
|
||||
|
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
18
.github/ISSUE_TEMPLATE/bug_report.md
vendored
@@ -19,24 +19,26 @@ labels: 'bug'
|
||||
|
||||
## Environment
|
||||
|
||||
Joplin version:
|
||||
Platform:
|
||||
OS specifcs:
|
||||
Joplin version:
|
||||
Platform:
|
||||
OS specifics:
|
||||
|
||||
<!--
|
||||
Platform can be one of: macOS, Linux, Windows, Android, iOS, terminal (or a combination)
|
||||
OS specifcs: e.g. OS version, Linux distribution, Android/iOS version, ...
|
||||
OS specifics: e.g. OS version, Linux distribution, Android/iOS version...
|
||||
-->
|
||||
|
||||
## Steps To Reproduce
|
||||
## Steps to reproduce
|
||||
|
||||
1.
|
||||
2.
|
||||
1.
|
||||
2.
|
||||
3.
|
||||
|
||||
<!--
|
||||
Issues without reproduction steps are likely to stall.
|
||||
-->
|
||||
|
||||
Describe what you expected to happen:
|
||||
## Describe what you expected to happen
|
||||
|
||||
|
||||
|
||||
|
1
.github/stale.yml
vendored
1
.github/stale.yml
vendored
@@ -12,6 +12,7 @@ exemptLabels:
|
||||
- "nice to have"
|
||||
- "upstream"
|
||||
- "backlog"
|
||||
- "high"
|
||||
# Label to use when marking an issue as stale
|
||||
staleLabel: stale
|
||||
# Comment to post when marking an issue as stale. Set to `false` to disable
|
||||
|
14
.gitignore
vendored
14
.gitignore
vendored
@@ -40,13 +40,19 @@ Tools/github_oauth_token.txt
|
||||
_releases
|
||||
ReactNativeClient/lib/csstojs/
|
||||
ReactNativeClient/lib/rnInjectedJs/
|
||||
ElectronClient/app/gui/note-viewer/fonts/
|
||||
ElectronClient/app/gui/note-viewer/lib.js
|
||||
ElectronClient/gui/note-viewer/fonts/
|
||||
ElectronClient/gui/note-viewer/lib.js
|
||||
Tools/commit_hook.txt
|
||||
.vscode/*
|
||||
*.map
|
||||
|
||||
# Ignore files generated from TypeScript files
|
||||
ElectronClient/app/gui/ShareNoteDialog.js
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
ElectronClient/gui/NoteContentPropertiesDialog.js
|
||||
ElectronClient/gui/ResourceScreen.js
|
||||
ElectronClient/gui/ShareNoteDialog.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/mermaid.js
|
||||
ReactNativeClient/lib/joplin-renderer/MdToHtml/rules/sanitize_html.js
|
||||
ReactNativeClient/lib/JoplinServerApi.js
|
||||
ReactNativeClient/PluginAssetsLoader.js
|
||||
ReactNativeClient/setUpQuickActions.js
|
||||
# AUTO-GENERATED - EXCLUDED TYPESCRIPT BUILD
|
||||
|
11
.travis.yml
11
.travis.yml
@@ -55,12 +55,8 @@ before_install:
|
||||
|
||||
script:
|
||||
- |
|
||||
# Copy lib
|
||||
rsync -aP --delete ReactNativeClient/lib/ ElectronClient/app/lib/
|
||||
|
||||
# Install tools
|
||||
npm install
|
||||
npm run tsc
|
||||
cd Tools
|
||||
npm install
|
||||
cd ..
|
||||
@@ -70,8 +66,7 @@ script:
|
||||
# and that would break the desktop release.
|
||||
if [ "$TRAVIS_PULL_REQUEST" != "false" ]; then
|
||||
cd CliClient
|
||||
npm install
|
||||
./run_test.sh
|
||||
npm run test
|
||||
testResult=$?
|
||||
if [ $testResult -ne 0 ]; then
|
||||
exit $testResult
|
||||
@@ -113,5 +108,5 @@ script:
|
||||
fi
|
||||
|
||||
# Prepare the Electron app and build it
|
||||
cd ElectronClient/app
|
||||
npm install && USE_HARD_LINKS=false yarn dist
|
||||
cd ElectronClient
|
||||
USE_HARD_LINKS=false yarn dist
|
||||
|
159
BUILD.md
159
BUILD.md
@@ -1,81 +1,104 @@
|
||||
[](https://travis-ci.org/laurent22/joplin) [](https://ci.appveyor.com/project/laurent22/joplin)
|
||||
|
||||
# General information
|
||||
# Building the applications
|
||||
|
||||
- All the applications share the same library, which, for historical reasons, is in ReactNativeClient/lib. This library is copied to the relevant directories when building each app.
|
||||
- In general, most of the backend (anything to do with the database, synchronisation, data import or export, etc.) is shared across all the apps, so when making a change please consider how it will affect all the apps.
|
||||
Note that all the applications share the same library, which, for historical reasons, is in `ReactNativeClient/lib`. This library is copied to the relevant directories when building each app.
|
||||
|
||||
# TypeScript
|
||||
|
||||
Most of the application is written in JavaScript, however new classes and files should generally be written in [TypeScript](https://www.typescriptlang.org/). Even if you don't write TypeScript code, you will need to build the existing .ts and .tsx files. This is done from the root of the project, by running `npm run tsc`.
|
||||
|
||||
If you are modifying TypeScript code, the best is to have the compiler watch for changes from a terminal. To do so, run `npm run tsc-watch`.
|
||||
|
||||
All TypeScript files are generated next to the .ts or .tsx file. So for example, if there's a file "lib/MyClass.ts", there will be a generated "lib/MyClass.js" next to it. If you create a new TypeScript file, make sure you add the generated .js file to .gitignore. It is implemented that way as it requires minimal changes to integrate TypeScript in the existing JavaScript code base.
|
||||
|
||||
## macOS dependencies
|
||||
|
||||
brew install yarn node
|
||||
echo 'export PATH="/usr/local/opt/gettext/bin:$PATH"' >> ~/.bash_profile
|
||||
source ~/.bash_profile
|
||||
|
||||
## Linux and Windows (WSL) dependencies
|
||||
## Required dependencies
|
||||
|
||||
- Install yarn - https://yarnpkg.com/lang/en/docs/install/
|
||||
- Install node v10.x (check with `node --version`) - https://nodejs.org/en/
|
||||
- If you get a node-gyp related error you might need to manually install it: `npm install -g node-gyp`
|
||||
- Install node - https://nodejs.org/en/
|
||||
|
||||
# Building the tools
|
||||
## Building
|
||||
|
||||
Before building any of the applications, you need to build the tools and pre-commit hooks:
|
||||
Before doing anything else, from the root of the project, run:
|
||||
|
||||
```
|
||||
npm install && cd Tools && npm install && cd ..
|
||||
npm install
|
||||
|
||||
Then you can test the various applications:
|
||||
|
||||
## Testing the desktop application
|
||||
|
||||
cd ElectronClient
|
||||
npm run start
|
||||
|
||||
If you'd like to auto-reload the app on changes rather than having to quit and restart it manually each time, you can use [watchman-make](https://facebook.github.io/watchman/docs/watchman-make.html):
|
||||
|
||||
```sh
|
||||
cd ElectronClient
|
||||
watchman-make -p '**/*.js' '**/*.jsx' --run "npm run start"
|
||||
```
|
||||
|
||||
# Building the Electron application
|
||||
It still requires you to quit the application each time you want it to rebuild, but at least you don't have to re-run `"npm run start"` each time. Here's what the workflow loop looks like in practice:
|
||||
|
||||
## Linux and macOS
|
||||
1. Edit and save files in your text editor.
|
||||
2. Switch to the Electron app and <kbd>cmd</kbd>+<kbd>Q</kbd> to quit it.
|
||||
3. `watchman` immediately restarts the app for you (whereas usually you'd have to switch back to the terminal, type `"npm run start"`, and hit enter).
|
||||
|
||||
```
|
||||
npm run copyLib
|
||||
npm run tsc
|
||||
cd ElectronClient/app
|
||||
npm install
|
||||
yarn dist
|
||||
```
|
||||
## Testing the Terminal application
|
||||
|
||||
cd CliClient
|
||||
npm run start
|
||||
|
||||
## Testing the Mobile application
|
||||
|
||||
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "React Native CLI Quickstart" tab.
|
||||
|
||||
Then:
|
||||
|
||||
cd ReactNativeClient
|
||||
npm run start-android
|
||||
# Or: npm run start-ios
|
||||
|
||||
To run the iOS application, it might be easier to open the file `ios/Joplin.xcworkspace` on XCode and run the app from there.
|
||||
|
||||
Normally the bundler should start automatically with the application. If it doesn't run `npm run start`.
|
||||
|
||||
## Building the clipper
|
||||
|
||||
cd Clipper/popup
|
||||
npm install
|
||||
npm run watch # To watch for changes
|
||||
|
||||
To test the extension please refer to the relevant pages for each browser: [Firefox](https://developer.mozilla.org/en-US/docs/Mozilla/Add-ons/WebExtensions/Your_first_WebExtension#Trying_it_out) / [Chrome](https://developer.chrome.com/extensions/faq#faq-dev-01). Please note that the extension in dev mode will only connect to a dev instance of the desktop app (and vice-versa).
|
||||
|
||||
## Watching files
|
||||
|
||||
To make changes to the application, you'll need to rebuild any TypeScript file you've changed, and rebuild the lib. The simplest way to do all this is to watch for changes from the root of the project. Simply run this command, and it should take care of the rest:
|
||||
|
||||
npm run watch
|
||||
|
||||
Running `npm run build` would have the same effect, but without watching.
|
||||
|
||||
## Running an application with additional parameters
|
||||
|
||||
You can specify additional parameters when running the desktop or CLI application. To do so, add `--` to the `npm run start` command, followed by your flags. For example:
|
||||
|
||||
npm run start -- --profile ~/MyTestProfile
|
||||
|
||||
## TypeScript
|
||||
|
||||
Most of the application is written in JavaScript, however new classes and files should generally be written in [TypeScript](https://www.typescriptlang.org/). All TypeScript files are generated next to the .ts or .tsx file. So for example, if there's a file "lib/MyClass.ts", there will be a generated "lib/MyClass.js" next to it. It is implemented that way as it requires minimal changes to integrate TypeScript in the existing JavaScript code base.
|
||||
|
||||
# Troubleshooting desktop application
|
||||
|
||||
## On Linux and macOS
|
||||
|
||||
If there's an error `while loading shared libraries: libgconf-2.so.4: cannot open shared object file: No such file or directory`, run `sudo apt-get install libgconf-2-4`
|
||||
|
||||
If you get a node-gyp related error you might need to manually install it: `npm install -g node-gyp`.
|
||||
If you get a node-gyp related error, you might need to manually install it: `npm install -g node-gyp`.
|
||||
|
||||
If you get the error `libtool: unrecognized option '-static'`, follow the instructions [in this post](https://stackoverflow.com/a/38552393/561309) to use the correct libtool version.
|
||||
|
||||
That will create the executable file in the `dist` directory.
|
||||
## On Windows
|
||||
|
||||
From `/ElectronClient` you can also run `run.sh` to run the app for testing.
|
||||
|
||||
## Windows
|
||||
|
||||
Run the following commands on Windows Command prompt running as Administrator:
|
||||
|
||||
```
|
||||
xcopy /C /I /H /R /Y /S ReactNativeClient\lib ElectronClient\app\lib
|
||||
npm run tsc
|
||||
cd ElectronClient\app
|
||||
npm install
|
||||
yarn dist
|
||||
```
|
||||
|
||||
If node-gyp does not works (MSBUILD: error MSB3428: Could not load the Visual C++ component "VCBuild.exe"), you might need to install the `windows-build-tools` using `npm install --global windows-build-tools`.
|
||||
If node-gyp does not work (MSBUILD: error MSB3428: Could not load the Visual C++ component "VCBuild.exe"), you might need to install `windows-build-tools` using `npm install --global windows-build-tools`.
|
||||
|
||||
If `yarn dist` fails, it may need administrative rights.
|
||||
|
||||
If you get an `error MSB8020: The build tools for v140 cannot be found.` try to run with a different toolset version, eg `npm install --toolset=v141` (See [here](https://github.com/mapbox/node-sqlite3/issues/1124) for more info).
|
||||
|
||||
The [building\_win32\_tips on this page](./readme/building_win32_tips.md) might be helpful.
|
||||
|
||||
## Troubleshooting desktop application
|
||||
## Other issues
|
||||
|
||||
> The application window doesn't open or is white
|
||||
|
||||
@@ -84,34 +107,10 @@ This is an indication that there's an early initialisation error. Try this:
|
||||
- In ElectronAppWrapper, set `debugEarlyBugs` to `true`. This will force the window to show up and should open the console next to it, which should display any error.
|
||||
- In more rare cases, an already open instance of Joplin can create strange low-level bugs that will display no error but will result in this white window. A non-dev instance of Joplin, or a dev instance that wasn't properly closed might cause this. So make sure you close everything and try again. Perhaps even other Electron apps running (Skype, Slack, etc.) could cause this?
|
||||
- Also try to delete node_modules and rebuild.
|
||||
- If all else fail, switch your computer off and on again, to make sure you start clean.
|
||||
- If all else fails, switch your computer off and on again, to make sure you start clean.
|
||||
|
||||
> How to work on the app from Windows?
|
||||
|
||||
You should not use WSL at all because this is a GUI app that lives outside of WSL, and the WSL layer can cause all kind of very hard to debug issues. It can also lock files in node_modules that cannot be unlocked when the app crashes (you need to restart your computer). Likewise, don't run the TypeScript watch command from WSL.
|
||||
**You should not use WSL at all** because this is a GUI app that lives outside of WSL, and the WSL layer can cause all kind of very hard to debug issues. It can also lock files in node_modules that cannot be unlocked when the app crashes. (You need to restart your computer.) Likewise, don't run the TypeScript watch command from WSL.
|
||||
|
||||
So everything should be done from a Windows Command prompt running as Administrator. You can use `run.bat` to run the app in dev mode.
|
||||
|
||||
# Building the Mobile application
|
||||
|
||||
First you need to setup React Native to build projects with native code. For this, follow the instructions on the [Get Started](https://facebook.github.io/react-native/docs/getting-started.html) tutorial, in the "React Native CLI Quickstart" tab.
|
||||
|
||||
Then:
|
||||
|
||||
```
|
||||
npm run tsc
|
||||
cd ReactNativeClient
|
||||
npm install
|
||||
react-native run-ios
|
||||
# Or: react-native run-android
|
||||
```
|
||||
|
||||
# Building the Terminal application
|
||||
|
||||
```
|
||||
cd CliClient
|
||||
npm install
|
||||
./build.sh
|
||||
```
|
||||
|
||||
Run `run.sh` to start the application for testing.
|
||||
So everything should be done from a Windows Command prompt or Windows PowerShell running as Administrator. All build and start commands are designed to work cross-platform, including on Windows.
|
||||
|
@@ -37,6 +37,7 @@ If you want to start contributing to the project's code, please follow these gui
|
||||
- A good way to easily start contributing is to pick and work on a [good first issue](https://github.com/laurent22/joplin/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22). We try to make these issues as clear as possible and provide basic info on how the code should be changed, and if something is unclear feel free to ask for more information on the issue.
|
||||
- Before adding a new feature, ask about it in the [Github Issue Tracker](https://github.com/laurent22/joplin/issues?utf8=%E2%9C%93&q=is%3Aissue) or the [Joplin Forum](https://discourse.joplinapp.org/), or check if existing discussions exist to make sure the new functionality is desired.
|
||||
- **Changes that will consist in more than 50 lines of code should be discussed the [Joplin Forum](https://discourse.joplinapp.org/)**, so that you don't spend too much time implementing something that might not be accepted.
|
||||
- All the applications share the same backend (database, synchronisation, settings, models, business logic, etc.) so if you change something in the backend in one app, makes sure it still work in the other apps. Usually it does, but keep this in mind.
|
||||
|
||||
Building the apps is relatively easy - please [see the build instructions](https://github.com/laurent22/joplin/blob/master/BUILD.md) for more details.
|
||||
|
||||
@@ -46,27 +47,39 @@ Coding style is enforced by a pre-commit hook that runs eslint. This hook is ins
|
||||
|
||||
For new React components, please use [React Hooks](https://reactjs.org/docs/hooks-intro.html). For new code in general, please use TypeScript (unless you are modifying a file that was originally in JavaScript).
|
||||
|
||||
For changes made to the Desktop client that affect the user interface, refer to `ElectronClient/app/theme.js` for all styling information. The goal is to create a consistent user interface to allow for easy navigation of Joplin's various features and improve the overall user experience.
|
||||
|
||||
### Unit tests
|
||||
|
||||
When submitting a pull request for a new feature or bug fix, please add unit tests for your code. Unit testing GUI changes is not always possible so it is not required, but any change in a file under /lib for example should be unit tested.
|
||||
|
||||
The tests are under CliClient/tests. To get them running, you first need to build the CLI app:
|
||||
|
||||
cd CliClient
|
||||
npm i
|
||||
./build.sh
|
||||
```sh
|
||||
npm run tsc # Build the .ts and .tsx files
|
||||
cd CliClient
|
||||
npm install
|
||||
```
|
||||
|
||||
To run all the test units:
|
||||
|
||||
./run_test.sh
|
||||
```sh
|
||||
npm run test
|
||||
```
|
||||
|
||||
To run just one particular file:
|
||||
|
||||
./run_test.sh markdownUtils # Don't add the .js extension
|
||||
```sh
|
||||
npm run test -- --filter=markdownUtils # Don't add the .js extension
|
||||
```
|
||||
|
||||
To filter tests:
|
||||
To filter tests. For example, to run all the test units that contain "should handle conflict" in their description:
|
||||
|
||||
./run_test.sh "should handle conflict" # Will run all the test units that contain "should handle conflict" in their description
|
||||
```sh
|
||||
npm run test -- --filter="should handle conflict"
|
||||
```
|
||||
|
||||
If you get the error `Cannot find module '/joplin/CliClient/node_modules/sqlite3/lib/binding/node-v79-darwin-x64/node_sqlite3.node'`, you may need to run `npm rebuild`.
|
||||
|
||||
## About abandoned pull requests
|
||||
|
||||
|
4
CliClient/.gitignore
vendored
4
CliClient/.gitignore
vendored
@@ -1,4 +1,3 @@
|
||||
build/
|
||||
node_modules/
|
||||
app/src
|
||||
tests-build/
|
||||
@@ -20,4 +19,5 @@ tests/sync
|
||||
out.txt
|
||||
linkToLocal.sh
|
||||
yarn-error.log
|
||||
tests/support/dropbox-auth.txt
|
||||
tests/support/dropbox-auth.txt
|
||||
build/
|
@@ -40,7 +40,7 @@ class FolderListWidget extends ListWidget {
|
||||
let output = 0;
|
||||
while (true) {
|
||||
const folder = BaseModel.byId(folders, folderId);
|
||||
if (!folder.parent_id) return output;
|
||||
if (!folder || !folder.parent_id) return output;
|
||||
output++;
|
||||
folderId = folder.parent_id;
|
||||
}
|
||||
|
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
./build.sh && NODE_PATH=build node build/build-doc.js
|
||||
npm run build && NODE_PATH=build node build/build-doc.js
|
@@ -1,16 +0,0 @@
|
||||
#!/bin/bash
|
||||
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
BUILD_DIR="$ROOT_DIR/build"
|
||||
|
||||
rsync -a --exclude "node_modules/" "$ROOT_DIR/app/" "$BUILD_DIR/"
|
||||
rsync -a --delete "$ROOT_DIR/../ReactNativeClient/lib/" "$BUILD_DIR/lib/"
|
||||
rsync -a --delete "$ROOT_DIR/../ReactNativeClient/locales/" "$BUILD_DIR/locales/"
|
||||
cp "$ROOT_DIR/package.json" "$BUILD_DIR"
|
||||
|
||||
# Don't add TypeScript here or make it silent as output of Cli app must be clean
|
||||
# cd $ROOT_DIR/..
|
||||
# npm run tsc
|
||||
# cd $ROOT_DIR
|
||||
|
||||
chmod 755 "$BUILD_DIR/main.js"
|
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
./build.sh && NODE_PATH="build/" node build/cli-integration-tests.js
|
||||
npm run build && NODE_PATH="build/" node build/cli-integration-tests.js
|
@@ -1,3 +1,3 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
./build.sh && NODE_PATH="build/" node build/fuzzing.js
|
||||
npm run build && NODE_PATH="build/" node build/fuzzing.js
|
40
CliClient/gulpfile.js
Normal file
40
CliClient/gulpfile.js
Normal file
@@ -0,0 +1,40 @@
|
||||
const gulp = require('gulp');
|
||||
const fs = require('fs-extra');
|
||||
const utils = require('../Tools/gulp/utils');
|
||||
const tasks = {
|
||||
copyLib: require('../Tools/gulp/tasks/copyLib'),
|
||||
};
|
||||
|
||||
tasks.build = {
|
||||
fn: async () => {
|
||||
const buildDir = `${__dirname}/build`;
|
||||
await utils.copyDir(`${__dirname}/app`, buildDir, {
|
||||
excluded: ['node_modules'],
|
||||
});
|
||||
await utils.copyDir(`${__dirname}/locales-build`, `${buildDir}/locales`);
|
||||
await tasks.copyLib.fn();
|
||||
await utils.copyFile(`${__dirname}/package.json`, `${buildDir}/package.json`);
|
||||
fs.chmodSync(`${buildDir}/main.js`, 0o755);
|
||||
},
|
||||
};
|
||||
|
||||
tasks.buildTests = {
|
||||
fn: async () => {
|
||||
const testBuildDir = `${__dirname}/tests-build`;
|
||||
|
||||
await utils.copyDir(`${__dirname}/tests`, testBuildDir, {
|
||||
excluded: [
|
||||
'lib/',
|
||||
'locales/',
|
||||
'node_modules/',
|
||||
],
|
||||
});
|
||||
|
||||
await utils.copyDir(`${__dirname}/../ReactNativeClient/lib`, `${testBuildDir}/lib`);
|
||||
await utils.copyDir(`${__dirname}/../ReactNativeClient/locales`, `${testBuildDir}/locales`);
|
||||
await fs.mkdirp(`${testBuildDir}/data`);
|
||||
},
|
||||
};
|
||||
|
||||
gulp.task('build', tasks.build.fn);
|
||||
gulp.task('buildTests', tasks.buildTests.fn);
|
1
CliClient/locales-build/ar.json
Normal file
1
CliClient/locales-build/ar.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/bg_BG.json
Normal file
1
CliClient/locales-build/bg_BG.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/bs_BA.json
Normal file
1
CliClient/locales-build/bs_BA.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/ca.json
Normal file
1
CliClient/locales-build/ca.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/cs_CZ.json
Normal file
1
CliClient/locales-build/cs_CZ.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/da_DK.json
Normal file
1
CliClient/locales-build/da_DK.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/de_DE.json
Normal file
1
CliClient/locales-build/de_DE.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/es_ES.json
Normal file
1
CliClient/locales-build/es_ES.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/et_EE.json
Normal file
1
CliClient/locales-build/et_EE.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/fa.json
Normal file
1
CliClient/locales-build/fa.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/fr_FR.json
Normal file
1
CliClient/locales-build/fr_FR.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/gl_ES.json
Normal file
1
CliClient/locales-build/gl_ES.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/hr_HR.json
Normal file
1
CliClient/locales-build/hr_HR.json
Normal file
File diff suppressed because one or more lines are too long
73
CliClient/locales-build/index.js
Normal file
73
CliClient/locales-build/index.js
Normal file
@@ -0,0 +1,73 @@
|
||||
var locales = {};
|
||||
var stats = {};
|
||||
locales['en_GB'] = require('./en_GB.json');
|
||||
locales['ar'] = require('./ar.json');
|
||||
locales['bg_BG'] = require('./bg_BG.json');
|
||||
locales['bs_BA'] = require('./bs_BA.json');
|
||||
locales['ca'] = require('./ca.json');
|
||||
locales['cs_CZ'] = require('./cs_CZ.json');
|
||||
locales['da_DK'] = require('./da_DK.json');
|
||||
locales['de_DE'] = require('./de_DE.json');
|
||||
locales['el_GR'] = require('./el_GR.json');
|
||||
locales['en_US'] = require('./en_US.json');
|
||||
locales['eo'] = require('./eo.json');
|
||||
locales['es_ES'] = require('./es_ES.json');
|
||||
locales['et_EE'] = require('./et_EE.json');
|
||||
locales['eu'] = require('./eu.json');
|
||||
locales['fa'] = require('./fa.json');
|
||||
locales['fr_FR'] = require('./fr_FR.json');
|
||||
locales['gl_ES'] = require('./gl_ES.json');
|
||||
locales['hr_HR'] = require('./hr_HR.json');
|
||||
locales['it_IT'] = require('./it_IT.json');
|
||||
locales['ja_JP'] = require('./ja_JP.json');
|
||||
locales['ko'] = require('./ko.json');
|
||||
locales['nb_NO'] = require('./nb_NO.json');
|
||||
locales['nl_BE'] = require('./nl_BE.json');
|
||||
locales['nl_NL'] = require('./nl_NL.json');
|
||||
locales['pl_PL'] = require('./pl_PL.json');
|
||||
locales['pt_BR'] = require('./pt_BR.json');
|
||||
locales['pt_PT'] = require('./pt_PT.json');
|
||||
locales['ro'] = require('./ro.json');
|
||||
locales['ru_RU'] = require('./ru_RU.json');
|
||||
locales['sl_SI'] = require('./sl_SI.json');
|
||||
locales['sr_RS'] = require('./sr_RS.json');
|
||||
locales['sv'] = require('./sv.json');
|
||||
locales['tr_TR'] = require('./tr_TR.json');
|
||||
locales['zh_CN'] = require('./zh_CN.json');
|
||||
locales['zh_TW'] = require('./zh_TW.json');
|
||||
stats['ar'] = { 'percentDone': 94 };
|
||||
stats['eu'] = { 'percentDone': 40 };
|
||||
stats['bs_BA'] = { 'percentDone': 88 };
|
||||
stats['bg_BG'] = { 'percentDone': 79 };
|
||||
stats['ca'] = { 'percentDone': 62 };
|
||||
stats['hr_HR'] = { 'percentDone': 33 };
|
||||
stats['cs_CZ'] = { 'percentDone': 97 };
|
||||
stats['da_DK'] = { 'percentDone': 87 };
|
||||
stats['de_DE'] = { 'percentDone': 98 };
|
||||
stats['et_EE'] = { 'percentDone': 78 };
|
||||
stats['en_GB'] = { 'percentDone': 100 };
|
||||
stats['en_US'] = { 'percentDone': 100 };
|
||||
stats['es_ES'] = { 'percentDone': 97 };
|
||||
stats['eo'] = { 'percentDone': 45 };
|
||||
stats['fr_FR'] = { 'percentDone': 98 };
|
||||
stats['gl_ES'] = { 'percentDone': 51 };
|
||||
stats['it_IT'] = { 'percentDone': 93 };
|
||||
stats['nl_NL'] = { 'percentDone': 89 };
|
||||
stats['nl_BE'] = { 'percentDone': 40 };
|
||||
stats['nb_NO'] = { 'percentDone': 91 };
|
||||
stats['fa'] = { 'percentDone': 39 };
|
||||
stats['pl_PL'] = { 'percentDone': 77 };
|
||||
stats['pt_PT'] = { 'percentDone': 93 };
|
||||
stats['pt_BR'] = { 'percentDone': 90 };
|
||||
stats['ro'] = { 'percentDone': 40 };
|
||||
stats['sl_SI'] = { 'percentDone': 51 };
|
||||
stats['sv'] = { 'percentDone': 69 };
|
||||
stats['tr_TR'] = { 'percentDone': 94 };
|
||||
stats['el_GR'] = { 'percentDone': 96 };
|
||||
stats['ru_RU'] = { 'percentDone': 98 };
|
||||
stats['sr_RS'] = { 'percentDone': 77 };
|
||||
stats['zh_CN'] = { 'percentDone': 97 };
|
||||
stats['zh_TW'] = { 'percentDone': 94 };
|
||||
stats['ja_JP'] = { 'percentDone': 98 };
|
||||
stats['ko'] = { 'percentDone': 92 };
|
||||
module.exports = { locales: locales, stats: stats };
|
1
CliClient/locales-build/it_IT.json
Normal file
1
CliClient/locales-build/it_IT.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/ja_JP.json
Normal file
1
CliClient/locales-build/ja_JP.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/ko.json
Normal file
1
CliClient/locales-build/ko.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/nb_NO.json
Normal file
1
CliClient/locales-build/nb_NO.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/nl_NL.json
Normal file
1
CliClient/locales-build/nl_NL.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/pl_PL.json
Normal file
1
CliClient/locales-build/pl_PL.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/pt_BR.json
Normal file
1
CliClient/locales-build/pt_BR.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/ro.json
Normal file
1
CliClient/locales-build/ro.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/sl_SI.json
Normal file
1
CliClient/locales-build/sl_SI.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/sr_RS.json
Normal file
1
CliClient/locales-build/sr_RS.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/sv.json
Normal file
1
CliClient/locales-build/sv.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/tr_TR.json
Normal file
1
CliClient/locales-build/tr_TR.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/zh_CN.json
Normal file
1
CliClient/locales-build/zh_CN.json
Normal file
File diff suppressed because one or more lines are too long
1
CliClient/locales-build/zh_TW.json
Normal file
1
CliClient/locales-build/zh_TW.json
Normal file
File diff suppressed because one or more lines are too long
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3297
CliClient/locales/et_EE.po
Normal file
3297
CliClient/locales/et_EE.po
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
3924
CliClient/package-lock.json
generated
3924
CliClient/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -3,6 +3,12 @@
|
||||
"description": "Joplin CLI Client",
|
||||
"license": "MIT",
|
||||
"author": "Laurent Cozic",
|
||||
"scripts": {
|
||||
"test": "gulp buildTests -L && jasmine --config=tests/support/jasmine.json",
|
||||
"postinstall": "patch-package && npm run build",
|
||||
"build": "gulp build",
|
||||
"start": "gulp build -L && node 'build/main.js' --profile ~/Temp/TestNotes2 --stack-trace-enabled --log-level debug --env dev"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/laurent22/joplin/issues"
|
||||
},
|
||||
@@ -32,6 +38,7 @@
|
||||
"app-module-path": "^2.2.0",
|
||||
"async-mutex": "^0.1.3",
|
||||
"base-64": "^0.1.0",
|
||||
"base64-stream": "^1.0.0",
|
||||
"clean-html": "^1.5.0",
|
||||
"compare-version": "^0.1.2",
|
||||
"diacritics": "^1.3.0",
|
||||
@@ -39,31 +46,50 @@
|
||||
"es6-promise-pool": "^2.5.0",
|
||||
"file-uri-to-path": "^1.0.0",
|
||||
"follow-redirects": "^1.2.4",
|
||||
"font-awesome-filetypes": "^2.1.0",
|
||||
"form-data": "^2.1.4",
|
||||
"fs-extra": "^5.0.0",
|
||||
"highlight.js": "^9.17.1",
|
||||
"html-entities": "^1.2.1",
|
||||
"html-minifier": "^3.5.15",
|
||||
"image-data-uri": "^2.0.0",
|
||||
"image-type": "^3.0.0",
|
||||
"joplin-turndown": "^4.0.19",
|
||||
"joplin-turndown-plugin-gfm": "^1.0.12",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"jssha": "^2.3.0",
|
||||
"katex": "^0.11.1",
|
||||
"levenshtein": "^1.0.5",
|
||||
"markdown-it": "^10.0.0",
|
||||
"markdown-it-abbr": "^1.0.4",
|
||||
"markdown-it-anchor": "^5.2.5",
|
||||
"markdown-it-deflist": "^2.0.3",
|
||||
"markdown-it-emoji": "^1.4.0",
|
||||
"markdown-it-expand-tabs": "^1.0.13",
|
||||
"markdown-it-footnote": "^3.0.2",
|
||||
"markdown-it-ins": "^3.0.0",
|
||||
"markdown-it-mark": "^3.0.0",
|
||||
"markdown-it-multimd-table": "^4.0.1",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"md5": "^2.2.1",
|
||||
"md5-file": "^4.0.0",
|
||||
"memory-cache": "^0.2.0",
|
||||
"mime": "^2.0.3",
|
||||
"moment": "^2.24.0",
|
||||
"multiparty": "^4.2.1",
|
||||
"node-emoji": "^1.8.1",
|
||||
"node-fetch": "^1.7.1",
|
||||
"node-persist": "^2.1.0",
|
||||
"patch-package": "^6.2.0",
|
||||
"promise": "^7.1.1",
|
||||
"proper-lockfile": "^2.0.1",
|
||||
"query-string": "4.3.4",
|
||||
"read-chunk": "^2.1.0",
|
||||
"redux": "^3.7.2",
|
||||
"request": "^2.88.0",
|
||||
"sax": "^1.2.2",
|
||||
"sax": "^1.2.4",
|
||||
"server-destroy": "^1.0.1",
|
||||
"sharp": "^0.23.2",
|
||||
"sprintf-js": "^1.1.1",
|
||||
@@ -77,33 +103,17 @@
|
||||
"terminal-kit": "^1.30.0",
|
||||
"tkwidgets": "^0.5.26",
|
||||
"url-parse": "^1.4.7",
|
||||
"uslug": "^1.0.4",
|
||||
"uuid": "^3.0.1",
|
||||
"valid-url": "^1.0.9",
|
||||
"word-wrap": "^1.2.3",
|
||||
"xml2js": "^0.4.19",
|
||||
"yargs-parser": "^7.0.0",
|
||||
"font-awesome-filetypes": "^2.1.0",
|
||||
"highlight.js": "^9.17.1",
|
||||
"json-stringify-safe": "^5.0.1",
|
||||
"katex": "^0.11.1",
|
||||
"markdown-it-abbr": "^1.0.4",
|
||||
"markdown-it-anchor": "^5.2.5",
|
||||
"markdown-it-deflist": "^2.0.3",
|
||||
"markdown-it-emoji": "^1.4.0",
|
||||
"markdown-it-expand-tabs": "^1.0.13",
|
||||
"markdown-it-footnote": "^3.0.2",
|
||||
"markdown-it-ins": "^3.0.0",
|
||||
"markdown-it-mark": "^3.0.0",
|
||||
"markdown-it-multimd-table": "^4.0.1",
|
||||
"markdown-it-sub": "^1.0.0",
|
||||
"markdown-it-sup": "^1.0.0",
|
||||
"markdown-it-toc-done-right": "^4.1.0",
|
||||
"uslug": "^1.0.4"
|
||||
"node-html-parser": "^1.2.4"
|
||||
},
|
||||
"devDependencies": {
|
||||
"jasmine": "^3.5.0"
|
||||
},
|
||||
"scripts": {
|
||||
"test": "jasmine"
|
||||
"gulp": "^4.0.2",
|
||||
"jasmine": "^3.5.0",
|
||||
"temp": "^0.9.1"
|
||||
}
|
||||
}
|
||||
|
18
CliClient/patches/sax+1.2.4.patch
Normal file
18
CliClient/patches/sax+1.2.4.patch
Normal file
@@ -0,0 +1,18 @@
|
||||
diff --git a/node_modules/sax/lib/sax.js b/node_modules/sax/lib/sax.js
|
||||
index 795d607..ccad5d8 100644
|
||||
--- a/node_modules/sax/lib/sax.js
|
||||
+++ b/node_modules/sax/lib/sax.js
|
||||
@@ -1040,6 +1040,13 @@
|
||||
parser.textNode += c
|
||||
}
|
||||
}
|
||||
+
|
||||
+ // Sax is kind of buggy when handling large text node. It has a function to check that
|
||||
+ // the buffer doesn't run out of space but it doesn't seem to call it for text node.
|
||||
+ // The result is that parser.textNode reaches 1GB and then the app crashes. So here
|
||||
+ // we call checkBufferLength to make sure the buffer is cleared and the "text" event
|
||||
+ // emitted so that the caller can handle memory properly.
|
||||
+ checkBufferLength(parser);
|
||||
continue
|
||||
|
||||
case S.SCRIPT:
|
@@ -1,21 +0,0 @@
|
||||
#!/bin/bash
|
||||
echo "Deprecated! Use `node Tools/release-cli.js`"
|
||||
exit 1
|
||||
|
||||
set -e
|
||||
|
||||
SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
cd "$SCRIPT_DIR"
|
||||
npm version patch
|
||||
touch "$SCRIPT_DIR/app/main.js"
|
||||
bash $SCRIPT_DIR/build.sh
|
||||
cp "$SCRIPT_DIR/package.json" build/
|
||||
cp "$SCRIPT_DIR/../README.md" build/
|
||||
cd "$SCRIPT_DIR/build"
|
||||
npm publish
|
||||
|
||||
NEW_VERSION=$(cat package.json | jq -r .version)
|
||||
git add -A
|
||||
git commit -m "CLI v$NEW_VERSION"
|
||||
git tag "cli-v$NEW_VERSION"
|
||||
git push && git push --tags
|
@@ -1,6 +0,0 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
CLIENT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
|
||||
bash "$CLIENT_DIR/build.sh" && node "$CLIENT_DIR/build/main.js" --profile ~/Temp/TestNotes2 --stack-trace-enabled --log-level debug --env dev "$@"
|
||||
# bash "$CLIENT_DIR/build.sh" && node "$CLIENT_DIR/build/main.js" --profile ~/.config/joplin --stack-trace-enabled --log-level debug --env dev "$@"
|
@@ -1,24 +0,0 @@
|
||||
#!/bin/bash
|
||||
START_DIR="$(pwd)"
|
||||
ROOT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
||||
BUILD_DIR="$ROOT_DIR/tests-build"
|
||||
FILTER="$1"
|
||||
|
||||
rsync -a --exclude "node_modules/" "$ROOT_DIR/tests/" "$BUILD_DIR/"
|
||||
rsync -a "$ROOT_DIR/../ReactNativeClient/lib/" "$BUILD_DIR/lib/"
|
||||
rsync -a "$ROOT_DIR/../ReactNativeClient/locales/" "$BUILD_DIR/locales/"
|
||||
mkdir -p "$BUILD_DIR/data"
|
||||
|
||||
function finish {
|
||||
cd "$START_DIR"
|
||||
}
|
||||
|
||||
trap finish EXIT
|
||||
|
||||
cd "$ROOT_DIR"
|
||||
|
||||
if [[ $FILTER != "" ]]; then
|
||||
npx jasmine --config=tests/support/jasmine.json --filter="$FILTER"
|
||||
else
|
||||
npx jasmine --config=tests/support/jasmine.json
|
||||
fi
|
79
CliClient/tests/HtmlToHtml.js
Normal file
79
CliClient/tests/HtmlToHtml.js
Normal file
@@ -0,0 +1,79 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
const os = require('os');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const { filename } = require('lib/path-utils.js');
|
||||
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const Note = require('lib/models/Note.js');
|
||||
const BaseModel = require('lib/BaseModel.js');
|
||||
const { shim } = require('lib/shim');
|
||||
const HtmlToHtml = require('lib/joplin-renderer/HtmlToHtml');
|
||||
const { enexXmlToMd } = require('lib/import-enex-md-gen.js');
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60 * 60 * 1000; // Can run for a while since everything is in the same test unit
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
});
|
||||
|
||||
describe('HtmlToHtml', function() {
|
||||
|
||||
beforeEach(async (done) => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should convert from Html to Html', asyncTest(async () => {
|
||||
const basePath = `${__dirname}/html_to_html`;
|
||||
const files = await shim.fsDriver().readDirStats(basePath);
|
||||
const htmlToHtml = new HtmlToHtml();
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const htmlSourceFilename = files[i].path;
|
||||
if (htmlSourceFilename.indexOf('.src.html') < 0) continue;
|
||||
|
||||
const htmlSourceFilePath = `${basePath}/${htmlSourceFilename}`;
|
||||
const htmlDestPath = `${basePath}/${filename(filename(htmlSourceFilePath))}.dest.html`;
|
||||
|
||||
// if (htmlSourceFilename !== 'table_with_header.html') continue;
|
||||
|
||||
const htmlToHtmlOptions = {
|
||||
bodyOnly: true,
|
||||
};
|
||||
|
||||
const sourceHtml = await shim.fsDriver().readFile(htmlSourceFilePath);
|
||||
let expectedHtml = await shim.fsDriver().readFile(htmlDestPath);
|
||||
|
||||
const result = await htmlToHtml.render(sourceHtml, null, htmlToHtmlOptions);
|
||||
let actualHtml = result.html;
|
||||
|
||||
if (os.EOL === '\r\n') {
|
||||
expectedHtml = expectedHtml.replace(/\r\n/g, '\n');
|
||||
actualHtml = actualHtml.replace(/\r\n/g, '\n');
|
||||
}
|
||||
|
||||
if (actualHtml !== expectedHtml) {
|
||||
console.info('');
|
||||
console.info(`Error converting file: ${htmlSourceFilename}`);
|
||||
console.info('--------------------------------- Got:');
|
||||
console.info(actualHtml);
|
||||
console.info('--------------------------------- Raw:');
|
||||
console.info(actualHtml.split('\n'));
|
||||
console.info('--------------------------------- Expected:');
|
||||
console.info(expectedHtml.split('\n'));
|
||||
console.info('--------------------------------------------');
|
||||
console.info('');
|
||||
|
||||
expect(false).toBe(true);
|
||||
// return;
|
||||
} else {
|
||||
expect(true).toBe(true);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
});
|
79
CliClient/tests/MdToHtml.js
Normal file
79
CliClient/tests/MdToHtml.js
Normal file
@@ -0,0 +1,79 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
|
||||
require('app-module-path').addPath(__dirname);
|
||||
|
||||
const os = require('os');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const { filename } = require('lib/path-utils.js');
|
||||
const { asyncTest, fileContentEqual, setupDatabase, setupDatabaseAndSynchronizer, db, synchronizer, fileApi, sleep, clearDatabase, switchClient, syncTargetId, objectsEqual, checkThrowAsync } = require('test-utils.js');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const Note = require('lib/models/Note.js');
|
||||
const BaseModel = require('lib/BaseModel.js');
|
||||
const { shim } = require('lib/shim');
|
||||
const MdToHtml = require('lib/joplin-renderer/MdToHtml');
|
||||
const { enexXmlToMd } = require('lib/import-enex-md-gen.js');
|
||||
|
||||
jasmine.DEFAULT_TIMEOUT_INTERVAL = 60 * 60 * 1000; // Can run for a while since everything is in the same test unit
|
||||
|
||||
process.on('unhandledRejection', (reason, p) => {
|
||||
console.log('Unhandled Rejection at: Promise', p, 'reason:', reason);
|
||||
});
|
||||
|
||||
describe('MdToHtml', function() {
|
||||
|
||||
beforeEach(async (done) => {
|
||||
await setupDatabaseAndSynchronizer(1);
|
||||
await switchClient(1);
|
||||
done();
|
||||
});
|
||||
|
||||
it('should convert from Markdown to Html', asyncTest(async () => {
|
||||
const basePath = `${__dirname}/md_to_html`;
|
||||
const files = await shim.fsDriver().readDirStats(basePath);
|
||||
const mdToHtml = new MdToHtml();
|
||||
|
||||
for (let i = 0; i < files.length; i++) {
|
||||
const mdFilename = files[i].path;
|
||||
if (mdFilename.indexOf('.md') < 0) continue;
|
||||
|
||||
const mdFilePath = `${basePath}/${mdFilename}`;
|
||||
const htmlPath = `${basePath}/${filename(mdFilePath)}.html`;
|
||||
|
||||
// if (mdFilename !== 'table_with_header.html') continue;
|
||||
|
||||
const mdToHtmlOptions = {
|
||||
bodyOnly: true,
|
||||
};
|
||||
|
||||
const markdown = await shim.fsDriver().readFile(mdFilePath);
|
||||
let expectedHtml = await shim.fsDriver().readFile(htmlPath);
|
||||
|
||||
const result = await mdToHtml.render(markdown, null, mdToHtmlOptions);
|
||||
let actualHtml = result.html;
|
||||
|
||||
if (os.EOL === '\r\n') {
|
||||
expectedHtml = expectedHtml.replace(/\r\n/g, '\n');
|
||||
actualHtml = actualHtml.replace(/\r\n/g, '\n');
|
||||
}
|
||||
|
||||
if (actualHtml !== expectedHtml) {
|
||||
console.info('');
|
||||
console.info(`Error converting file: ${mdFilename}`);
|
||||
console.info('--------------------------------- Got:');
|
||||
console.info(actualHtml);
|
||||
console.info('--------------------------------- Raw:');
|
||||
console.info(actualHtml.split('\n'));
|
||||
console.info('--------------------------------- Expected:');
|
||||
console.info(expectedHtml.split('\n'));
|
||||
console.info('--------------------------------------------');
|
||||
console.info('');
|
||||
|
||||
expect(false).toBe(true);
|
||||
// return;
|
||||
} else {
|
||||
expect(true).toBe(true);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
});
|
@@ -20,6 +20,7 @@ describe('htmlUtils', function() {
|
||||
['<img src="http://test.com/img.png"/>', ['http://test.com/img.png']],
|
||||
['<img src="http://test.com/img.png"/> <img src="http://test.com/img2.png"/>', ['http://test.com/img.png', 'http://test.com/img2.png']],
|
||||
['<img src="http://test.com/img.png" alt="testing" >', ['http://test.com/img.png']],
|
||||
['<img src=""/> <img src="http://test.com/img2.png"/>', ['http://test.com/img2.png']],
|
||||
['nothing here', []],
|
||||
['', []],
|
||||
];
|
||||
|
2
CliClient/tests/html_to_html/sanitize.dest.html
Normal file
2
CliClient/tests/html_to_html/sanitize.dest.html
Normal file
@@ -0,0 +1,2 @@
|
||||
<img src onerror="" />
|
||||
<img src onerror="" />
|
3
CliClient/tests/html_to_html/sanitize.src.html
Normal file
3
CliClient/tests/html_to_html/sanitize.src.html
Normal file
@@ -0,0 +1,3 @@
|
||||
<img src="" onerror="alert('ohno')"/>
|
||||
<img src=""
|
||||
onerror="alert('ohno')"/>
|
93
CliClient/tests/integration_ShowAllNotes.js
Normal file
93
CliClient/tests/integration_ShowAllNotes.js
Normal file
@@ -0,0 +1,93 @@
|
||||
/* eslint-disable no-unused-vars */
|
||||
require('app-module-path').addPath(__dirname);
|
||||
const { setupDatabaseAndSynchronizer, switchClient, asyncTest, id, ids, sortedIds, at, createNTestFolders, createNTestNotes, createNTestTags, TestApp } = require('test-utils.js');
|
||||
const Setting = require('lib/models/Setting.js');
|
||||
const Folder = require('lib/models/Folder.js');
|
||||
const Note = require('lib/models/Note.js');
|
||||
const Tag = require('lib/models/Tag.js');
|
||||
const { time } = require('lib/time-utils.js');
|
||||
const { ALL_NOTES_FILTER_ID } = require('lib/reserved-ids.js');
|
||||
|
||||
//
|
||||
// The integration tests are to test the integration of the core system, comprising the
|
||||
// base application with middleware, reducer and models in response to dispatched events.
|
||||
//
|
||||
// The general strategy for each integration test is:
|
||||
// - create a starting application state,
|
||||
// - inject the event to be tested
|
||||
// - check the resulting application state
|
||||
//
|
||||
// Important: sleep must be used after TestApp dispatch to allow the async processing
|
||||
// to complete
|
||||
//
|
||||
|
||||
// use this until Javascript arr.flat() function works in Travis
|
||||
function flatten(arr) {
|
||||
return (arr.reduce((acc, val) => acc.concat(val), []));
|
||||
}
|
||||
|
||||
let testApp = null;
|
||||
|
||||
describe('integration_ShowAllNotes', function() {
|
||||
|
||||
beforeEach(async (done) => {
|
||||
testApp = new TestApp();
|
||||
await testApp.start(['--no-welcome']);
|
||||
done();
|
||||
});
|
||||
|
||||
afterEach(async (done) => {
|
||||
if (testApp !== null) await testApp.destroy();
|
||||
testApp = null;
|
||||
done();
|
||||
});
|
||||
|
||||
it('should show all notes', asyncTest(async () => {
|
||||
// setup
|
||||
let folders = await createNTestFolders(3);
|
||||
Folder.moveToFolder(id(folders[2]), id(folders[1])); // subfolder
|
||||
await time.msleep(100);
|
||||
let notes0 = await createNTestNotes(3, folders[0]);
|
||||
let notes1 = await createNTestNotes(3, folders[1]);
|
||||
let notes2 = await createNTestNotes(3, folders[2]);
|
||||
|
||||
// TEST ACTION: View all-notes
|
||||
testApp.dispatch({ type: 'SMART_FILTER_SELECT', id: ALL_NOTES_FILTER_ID });
|
||||
await time.msleep(100);
|
||||
|
||||
// check: all the notes are shown
|
||||
let state = testApp.store().getState();
|
||||
expect(state.notesParentType).toEqual('SmartFilter');
|
||||
expect(state.selectedSmartFilterId).toEqual(ALL_NOTES_FILTER_ID);
|
||||
expect(sortedIds(state.notes)).toEqual(sortedIds(notes0.concat(notes1).concat(notes2)));
|
||||
}));
|
||||
|
||||
it('should show retain note selection when going from a folder to all-notes', asyncTest(async () => {
|
||||
// setup
|
||||
let folders = await createNTestFolders(2);
|
||||
let notes0 = await createNTestNotes(3, folders[0]);
|
||||
let notes1 = await createNTestNotes(3, folders[1]);
|
||||
testApp.dispatch({ type: 'FOLDER_SELECT', id: id(folders[1]) });
|
||||
await time.msleep(100);
|
||||
testApp.dispatch({ type: 'NOTE_SELECT', id: id(notes1[1]) });
|
||||
await time.msleep(100);
|
||||
|
||||
// check the state is set up as expected
|
||||
let state = testApp.store().getState();
|
||||
expect(state.notesParentType).toEqual('Folder');
|
||||
expect(state.selectedFolderId).toEqual(id(folders[1]));
|
||||
expect(sortedIds(state.notes)).toEqual(sortedIds(notes1));
|
||||
expect(state.selectedNoteIds).toEqual(ids([notes1[1]]));
|
||||
|
||||
// TEST ACTION: View all-notes
|
||||
testApp.dispatch({ type: 'SMART_FILTER_SELECT', id: ALL_NOTES_FILTER_ID });
|
||||
await time.msleep(100);
|
||||
|
||||
// check: all the notes are shown
|
||||
state = testApp.store().getState();
|
||||
expect(state.notesParentType).toEqual('SmartFilter');
|
||||
expect(state.selectedSmartFilterId).toEqual(ALL_NOTES_FILTER_ID);
|
||||
expect(sortedIds(state.notes)).toEqual(sortedIds(notes0.concat(notes1)));
|
||||
expect(state.selectedNoteIds).toEqual(ids([notes1[1]]));
|
||||
}));
|
||||
});
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user