mirror of
https://github.com/streetwriters/notesnook.git
synced 2026-08-31 11:08:47 +02:00
Compare commits
52 Commits
mobile-fix
...
3.3.4-andr
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
070c90362a | ||
|
|
2685f60409 | ||
|
|
1427958eca | ||
|
|
436e09c255 | ||
|
|
cc9b2dd5b0 | ||
|
|
0ba25419f3 | ||
|
|
9238de4cb4 | ||
|
|
2d5fe1058c | ||
|
|
b01d1fc87e | ||
|
|
9f4c0a4c9a | ||
|
|
9eebda86c2 | ||
|
|
d43e856fea | ||
|
|
7af1596038 | ||
|
|
652f6eab0b | ||
|
|
9a1adf2065 | ||
|
|
f10b258f58 | ||
|
|
641eb28ce7 | ||
|
|
2c59a5f6f9 | ||
|
|
e5ad405a23 | ||
|
|
cd1b78d8df | ||
|
|
3b1ca46945 | ||
|
|
96c1636f88 | ||
|
|
9ff4757ed6 | ||
|
|
17c1e77f54 | ||
|
|
187a2a7262 | ||
|
|
4621230549 | ||
|
|
d7cb3317a2 | ||
|
|
6d81f26864 | ||
|
|
2341293d92 | ||
|
|
215387f8a9 | ||
|
|
534b8c5ad0 | ||
|
|
b7b2ead9eb | ||
|
|
b3e34d68e1 | ||
|
|
39079612aa | ||
|
|
be1af3111f | ||
|
|
8dcff49797 | ||
|
|
687fb4e105 | ||
|
|
25ae780ad8 | ||
|
|
b695367e6c | ||
|
|
bb274a84fe | ||
|
|
364dccbf7a | ||
|
|
105fb0fc69 | ||
|
|
110534edec | ||
|
|
00e2190b2d | ||
|
|
e5c3fc667e | ||
|
|
9aef8194f9 | ||
|
|
f76e0b7931 | ||
|
|
0457e4417f | ||
|
|
dae8b5c542 | ||
|
|
60107dd77f | ||
|
|
4f3e19aaa2 | ||
|
|
c77050eccc |
@@ -7,7 +7,7 @@ runs:
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v4
|
||||
with:
|
||||
node-version: 20.x
|
||||
node-version: 22.x
|
||||
cache: "npm"
|
||||
cache-dependency-path: |
|
||||
package-lock.json
|
||||
|
||||
3
.github/workflows/core.tests.yml
vendored
3
.github/workflows/core.tests.yml
vendored
@@ -52,7 +52,6 @@ jobs:
|
||||
echo "USER_PASSWORD=${{ secrets.USER_PASSWORD }}" >> $GITHUB_ENV
|
||||
echo "USER_TOTP_SECRET=${{ secrets.USER_TOTP_SECRET }}" >> $GITHUB_ENV
|
||||
echo "USER_HASHED_PASSWORD=${{ secrets.USER_HASHED_PASSWORD }}" >> $GITHUB_ENV
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Run all @notesnook/core tests
|
||||
run: npx nx test:e2e @notesnook/core
|
||||
run: npm run tx @notesnook/core:test:e2e
|
||||
|
||||
22
.github/workflows/desktop.publish.yml
vendored
22
.github/workflows/desktop.publish.yml
vendored
@@ -65,17 +65,13 @@ jobs:
|
||||
npm i --cpu x64 sqlite-better-trigram
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate desktop build (stable)
|
||||
if: ${{ inputs.release-track == 'stable' }}
|
||||
run: npx nx build:desktop @notesnook/web
|
||||
run: npm run tx @notesnook/web:build:desktop
|
||||
|
||||
- name: Generate desktop build (beta)
|
||||
if: ${{ inputs.release-track == 'beta' }}
|
||||
run: BETA=true npx nx build:desktop @notesnook/web
|
||||
run: BETA=true npm run tx @notesnook/web:build:desktop
|
||||
|
||||
- name: Build desktop bundle
|
||||
working-directory: ./apps/desktop
|
||||
@@ -199,9 +195,9 @@ jobs:
|
||||
CSC_LINK: ${{ secrets.mac_certs }}
|
||||
CSC_KEY_PASSWORD: ${{ secrets.mac_certs_password }}
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop -- --variant=mas
|
||||
npm run tx @notesnook/desktop:release -- --variant=mas
|
||||
cd apps/desktop
|
||||
yarn electron-builder --config=electron-builder.config.js --mac mas --universal -p never
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build zip and dmg
|
||||
env:
|
||||
@@ -212,13 +208,13 @@ jobs:
|
||||
APPLE_API_KEY_ID: ${{ secrets.api_key_id }}
|
||||
APPLE_API_ISSUER: ${{ secrets.api_key_issuer_id }}
|
||||
run: |
|
||||
npx nx run release --project @notesnook/desktop
|
||||
npm run tx @notesnook/desktop:release
|
||||
cd apps/desktop
|
||||
if [ ${{ inputs.publish-github }} == true ]; then
|
||||
yarn electron-builder --config=electron-builder.config.js --mac zip dmg --arm64 --x64 -p always
|
||||
else
|
||||
yarn electron-builder --config=electron-builder.config.js --mac zip dmg --arm64 --x64 -p never
|
||||
fi
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Deploy to Testflight
|
||||
if: inputs.publish-apple && steps.appstore.outputs.app-version-latest != steps.app_metadata.outputs.app_version
|
||||
@@ -271,8 +267,7 @@ jobs:
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build snap
|
||||
if: inputs.publish-snap
|
||||
@@ -339,8 +334,7 @@ jobs:
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
# - name: Build snap
|
||||
# if: inputs.publish-snap
|
||||
|
||||
15
.github/workflows/desktop.tests.yml
vendored
15
.github/workflows/desktop.tests.yml
vendored
@@ -33,12 +33,8 @@ jobs:
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=web
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate desktop build
|
||||
run: npx nx build:desktop @notesnook/web
|
||||
run: npm run tx @notesnook/web:build:desktop
|
||||
|
||||
- name: Archive build artifact
|
||||
uses: actions/upload-artifact@v4
|
||||
@@ -70,8 +66,7 @@ jobs:
|
||||
npm run bootstrap -- --scope=desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
@@ -114,8 +109,7 @@ jobs:
|
||||
npm run bootstrap -- --scope=desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
@@ -164,8 +158,7 @@ jobs:
|
||||
working-directory: ./apps/desktop
|
||||
|
||||
- name: Build Electron wrapper
|
||||
run: npx nx run release --project @notesnook/desktop
|
||||
working-directory: ./apps/desktop
|
||||
run: npm run tx @notesnook/desktop:release
|
||||
|
||||
- name: Build app
|
||||
run: |
|
||||
|
||||
8
.github/workflows/editor.tests.yml
vendored
8
.github/workflows/editor.tests.yml
vendored
@@ -38,12 +38,8 @@ jobs:
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=editor
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build editor
|
||||
run: npx nx build @notesnook/editor
|
||||
run: npm run tx @notesnook/editor:build
|
||||
|
||||
- name: Run all @notesnook/editor tests
|
||||
run: npx nx test @notesnook/editor
|
||||
run: npm run tx @notesnook/editor:test
|
||||
|
||||
2
.github/workflows/ios.publish.yml
vendored
2
.github/workflows/ios.publish.yml
vendored
@@ -25,7 +25,7 @@ jobs:
|
||||
npm run bootstrap -- --scope=mobile
|
||||
|
||||
- name: Build packages
|
||||
run: npx nx run @notesnook/mobile:build
|
||||
run: npm run tx @notesnook/mobile:build
|
||||
|
||||
- name: ccache
|
||||
uses: hendrikmuhs/ccache-action@v1.2.11
|
||||
|
||||
2
.github/workflows/monograph.publish.yml
vendored
2
.github/workflows/monograph.publish.yml
vendored
@@ -39,7 +39,7 @@ jobs:
|
||||
echo ::set-output name=app_version::$(cat package.json | jq -r .version)
|
||||
|
||||
- name: Generate build
|
||||
run: npx nx build @notesnook/monograph
|
||||
run: npm run tx @notesnook/monograph:build
|
||||
|
||||
# Setup Buildx
|
||||
- name: Docker Setup Buildx
|
||||
|
||||
1
.github/workflows/theme-builder.publish.yml
vendored
1
.github/workflows/theme-builder.publish.yml
vendored
@@ -20,7 +20,6 @@ jobs:
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
|
||||
1
.github/workflows/vericrypt.publish.yml
vendored
1
.github/workflows/vericrypt.publish.yml
vendored
@@ -20,7 +20,6 @@ jobs:
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
|
||||
4
.github/workflows/web.benchmarks.yml
vendored
4
.github/workflows/web.benchmarks.yml
vendored
@@ -27,10 +27,6 @@ jobs:
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=web
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Build
|
||||
run: npm run build:web
|
||||
|
||||
|
||||
1
.github/workflows/web.publish.yml
vendored
1
.github/workflows/web.publish.yml
vendored
@@ -30,7 +30,6 @@ jobs:
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_ACCOUNT_ID=${{ secrets.CLOUDFLARE_ACCOUNT_ID }}" >> $GITHUB_ENV
|
||||
echo "CLOUDFLARE_API_TOKEN=${{ secrets.CLOUDFLARE_API_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
|
||||
4
.github/workflows/web.tests.yml
vendored
4
.github/workflows/web.tests.yml
vendored
@@ -49,10 +49,6 @@ jobs:
|
||||
npm ci --ignore-scripts --prefer-offline --no-audit
|
||||
npm run bootstrap -- --scope=web
|
||||
|
||||
- name: Setup environment
|
||||
run: |
|
||||
echo "NX_CLOUD_ACCESS_TOKEN=${{ secrets.NX_CLOUD_ACCESS_TOKEN }}" >> $GITHUB_ENV
|
||||
|
||||
- name: Generate test build
|
||||
run: npm run build:test:web
|
||||
|
||||
|
||||
@@ -27,7 +27,6 @@ Notesnook is built using the following technologies:
|
||||
3. React Native — For mobile apps we are using React Native
|
||||
4. Electron — For desktop app
|
||||
5. NPM — listed here because we **don't** use Yarn or PNPM or XYZ across any of our projects.
|
||||
6. Nx — maintaining monorepos is hard but Nx makes it easier.
|
||||
|
||||
> **Note: Each project in the monorepo contains its own architecture details which you can refer to.**
|
||||
|
||||
|
||||
12
apps/desktop/package-lock.json
generated
12
apps/desktop/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/desktop",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
@@ -30,7 +30,7 @@
|
||||
"@types/node": "22.15.3",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"chokidar": "^4.0.3",
|
||||
"electron": "^36.0.0",
|
||||
"electron": "^37.0.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"esbuild": "0.21.5",
|
||||
"node-abi": "^4.5.0",
|
||||
@@ -3584,9 +3584,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/electron": {
|
||||
"version": "36.9.3",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-36.9.3.tgz",
|
||||
"integrity": "sha512-eR5yswsA55zVTPDEIA/PSdVNBLOp0q0Wsavgx0S3BmJYOqKoH1gqzS+hggf0/aY5OvUjVNSHiJJA1VsB5aJUug==",
|
||||
"version": "37.6.1",
|
||||
"resolved": "https://registry.npmjs.org/electron/-/electron-37.6.1.tgz",
|
||||
"integrity": "sha512-aHtJVNjqf0lk7dlPoc1X+fMBpZtLn+XGvP6IYc3gooTwsD1D/Ic2SBRC9SnIk6LkWTsDaSF9jgH1d9Q7eABy/Q==",
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
"name": "@notesnook/desktop",
|
||||
"productName": "Notesnook",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"appAppleId": "1544027013",
|
||||
"private": true,
|
||||
"main": "./dist/cjs/index.js",
|
||||
@@ -47,7 +47,7 @@
|
||||
"@types/node": "22.15.3",
|
||||
"@types/yargs": "^17.0.33",
|
||||
"chokidar": "^4.0.3",
|
||||
"electron": "^36.0.0",
|
||||
"electron": "^37.0.0",
|
||||
"electron-builder": "^26.0.12",
|
||||
"esbuild": "0.21.5",
|
||||
"node-abi": "^4.5.0",
|
||||
|
||||
@@ -19,14 +19,11 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import {
|
||||
ScrollView,
|
||||
TouchableOpacity,
|
||||
View,
|
||||
useWindowDimensions
|
||||
} from "react-native";
|
||||
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
|
||||
import { SheetManager } from "react-native-actions-sheet";
|
||||
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
|
||||
import { DDS } from "../../services/device-detection";
|
||||
import { eSendEvent } from "../../services/event-manager";
|
||||
import Navigation from "../../services/navigation";
|
||||
@@ -47,8 +44,7 @@ import { hideAuth } from "./common";
|
||||
import { ForgotPassword } from "./forgot-password";
|
||||
import { AuthHeader } from "./header";
|
||||
import { useLogin } from "./use-login";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
|
||||
import SettingsService from "../../services/settings";
|
||||
|
||||
const LoginSteps = {
|
||||
emailAuth: 1,
|
||||
@@ -81,7 +77,7 @@ export const Login = ({ changeMode }) => {
|
||||
}
|
||||
}, 5000);
|
||||
|
||||
if (!PremiumService.get()) {
|
||||
if (!PremiumService.get() && !SettingsService.getProperty("serverUrls")) {
|
||||
Navigation.navigate("PayWall", {
|
||||
context: "signup",
|
||||
state: route.params.state,
|
||||
|
||||
@@ -19,6 +19,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
import React, { useRef, useState } from "react";
|
||||
import { TouchableOpacity, View, useWindowDimensions } from "react-native";
|
||||
import { KeyboardAwareScrollView } from "react-native-keyboard-aware-scroll-view";
|
||||
@@ -38,7 +39,6 @@ import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import { AuthHeader } from "./header";
|
||||
import { SignupContext } from "./signup-context";
|
||||
import { useRoute } from "@react-navigation/native";
|
||||
|
||||
const SignupSteps = {
|
||||
signup: 0,
|
||||
@@ -91,11 +91,13 @@ export const Signup = ({ changeMode, welcome }) => {
|
||||
setLastSynced(await db.lastSynced());
|
||||
clearMessage();
|
||||
setEmailVerifyMessage();
|
||||
Navigation.navigate("PayWall", {
|
||||
canGoBack: false,
|
||||
state: route.params.state,
|
||||
context: "signup"
|
||||
});
|
||||
if (!SettingsService.getProperty("serverUrls")) {
|
||||
Navigation.navigate("PayWall", {
|
||||
canGoBack: false,
|
||||
state: route.params.state,
|
||||
context: "signup"
|
||||
});
|
||||
}
|
||||
return true;
|
||||
} catch (e) {
|
||||
setCurrentStep(SignupSteps.signup);
|
||||
|
||||
@@ -60,6 +60,7 @@ import usePricingPlans, {
|
||||
PricingPlan
|
||||
} from "../../hooks/use-pricing-plans";
|
||||
import Navigation, { NavigationProps } from "../../services/navigation";
|
||||
import PremiumService from "../../services/premium";
|
||||
import { getElevationStyle } from "../../utils/elevation";
|
||||
import { openLinkInBrowser } from "../../utils/functions";
|
||||
import { AppFontSize, defaultBorderRadius } from "../../utils/size";
|
||||
@@ -74,7 +75,6 @@ import { IconButton } from "../ui/icon-button";
|
||||
import { SvgView } from "../ui/svg";
|
||||
import Heading from "../ui/typography/heading";
|
||||
import Paragraph from "../ui/typography/paragraph";
|
||||
import PremiumService from "../../services/premium";
|
||||
|
||||
const Steps = {
|
||||
select: 1,
|
||||
@@ -114,15 +114,8 @@ const PayWall = (props: NavigationProps<"PayWall">) => {
|
||||
routeParams.state?.planId,
|
||||
routeParams.state?.productId
|
||||
);
|
||||
console.log(
|
||||
"selectPlan",
|
||||
routeParams.state?.planId,
|
||||
routeParams.state?.productId,
|
||||
(pricingPlans.selectedProduct as any).productId
|
||||
);
|
||||
}
|
||||
setStep(Steps.buy);
|
||||
console.log("Buy step");
|
||||
}
|
||||
}, [routeParams.state]);
|
||||
|
||||
@@ -926,7 +919,6 @@ const ReviewItem = (props: {
|
||||
</View>
|
||||
);
|
||||
};
|
||||
|
||||
const PricingPlanCard = ({
|
||||
plan,
|
||||
pricingPlans,
|
||||
@@ -939,7 +931,6 @@ const PricingPlanCard = ({
|
||||
setStep: (step: number) => void;
|
||||
}) => {
|
||||
const { colors } = useThemeColors();
|
||||
const isFreePlan = plan.id === "free";
|
||||
const [regionalDiscount, setRegionaDiscount] = useState<SKUResponse>();
|
||||
const { width } = useWindowDimensions();
|
||||
const isTablet = width > 600;
|
||||
@@ -949,7 +940,6 @@ const PricingPlanCard = ({
|
||||
regionalDiscount?.sku ||
|
||||
`notesnook.${plan.id}.${annualBilling ? "yearly" : "monthly"}`
|
||||
];
|
||||
console.log(regionalDiscount?.sku);
|
||||
const price = pricingPlans?.getPrice(
|
||||
product as RNIap.Subscription,
|
||||
pricingPlans.hasTrialOffer(plan.id, product?.productId) ? 1 : 0,
|
||||
@@ -962,6 +952,7 @@ const PricingPlanCard = ({
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
if (pricingPlans?.isGithubRelease) return;
|
||||
pricingPlans
|
||||
?.getRegionalDiscount(
|
||||
plan.id,
|
||||
@@ -980,7 +971,7 @@ const PricingPlanCard = ({
|
||||
pricingPlans.isSubscribed();
|
||||
|
||||
const isNotReady =
|
||||
pricingPlans?.loadingPlans || (!price && !WebPlan?.price.gross);
|
||||
pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross);
|
||||
|
||||
return (
|
||||
<TouchableOpacity
|
||||
@@ -1003,8 +994,8 @@ const PricingPlanCard = ({
|
||||
: "monthly"
|
||||
}`
|
||||
: pricingPlans.isGithubRelease
|
||||
? (WebPlan?.period as string)
|
||||
: (product?.productId as string)
|
||||
? (WebPlan?.period as string)
|
||||
: (product?.productId as string)
|
||||
);
|
||||
setStep(Steps.buy);
|
||||
}}
|
||||
@@ -1112,29 +1103,26 @@ const PricingPlanCard = ({
|
||||
</View>
|
||||
</View>
|
||||
|
||||
{pricingPlans?.loadingPlans || (!price && !WebPlan?.price.gross) ? (
|
||||
{pricingPlans?.loadingPlans || (!price && !WebPlan?.price?.gross) ? (
|
||||
<ActivityIndicator size="small" color={colors.primary.accent} />
|
||||
) : (
|
||||
<View>
|
||||
<Paragraph size={AppFontSize.lg}>
|
||||
{isFreePlan
|
||||
? "0.00"
|
||||
: price ||
|
||||
`${WebPlan?.price.currency} ${WebPlan?.price.gross}`}{" "}
|
||||
{price || `${WebPlan?.price?.currency} ${WebPlan?.price?.gross}`}{" "}
|
||||
<Paragraph>/{strings.month()}</Paragraph>
|
||||
</Paragraph>
|
||||
|
||||
{isFreePlan || !product ? null : (
|
||||
{!product && !WebPlan ? null : (
|
||||
<Paragraph color={colors.secondary.paragraph} size={AppFontSize.xs}>
|
||||
{annualBilling
|
||||
? strings.billedAnnually(
|
||||
pricingPlans?.getStandardPrice(
|
||||
product as RNIap.Subscription
|
||||
(product as RNIap.Subscription) || (WebPlan as Plan)
|
||||
) as string
|
||||
)
|
||||
: strings.billedMonthly(
|
||||
pricingPlans?.getStandardPrice(
|
||||
product as RNIap.Subscription
|
||||
(product as RNIap.Subscription) || (WebPlan as Plan)
|
||||
) as string
|
||||
)}
|
||||
</Paragraph>
|
||||
|
||||
@@ -21,7 +21,13 @@ import { strings } from "@notesnook/intl";
|
||||
import { useThemeColors } from "@notesnook/theme";
|
||||
import dayjs from "dayjs";
|
||||
import React, { useEffect, useState } from "react";
|
||||
import { ScrollView, Text, TouchableOpacity, View } from "react-native";
|
||||
import {
|
||||
Linking,
|
||||
ScrollView,
|
||||
Text,
|
||||
TouchableOpacity,
|
||||
View
|
||||
} from "react-native";
|
||||
import Config from "react-native-config";
|
||||
import * as RNIap from "react-native-iap";
|
||||
import Icon from "react-native-vector-icons/MaterialCommunityIcons";
|
||||
@@ -60,27 +66,17 @@ export const BuyPlan = (props: {
|
||||
return checkoutUrl ? (
|
||||
<View
|
||||
style={{
|
||||
flex: 1
|
||||
flex: 1,
|
||||
justifyContent: "center",
|
||||
alignItems: "center",
|
||||
gap: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
<WebView
|
||||
source={{
|
||||
uri: checkoutUrl
|
||||
}}
|
||||
onMessage={(message) => {
|
||||
try {
|
||||
const data = JSON.parse(message.nativeEvent.data);
|
||||
if (data.success) {
|
||||
pricingPlans.finish();
|
||||
}
|
||||
} catch (e) {}
|
||||
}}
|
||||
domStorageEnabled
|
||||
javaScriptEnabled
|
||||
cacheEnabled
|
||||
enabled
|
||||
style={{
|
||||
flex: 1
|
||||
<Paragraph>{strings.finishPurchaseInBrowser()}</Paragraph>
|
||||
<Button
|
||||
title={strings.goBack()}
|
||||
onPress={() => {
|
||||
setCheckoutUrl(undefined);
|
||||
}}
|
||||
/>
|
||||
</View>
|
||||
@@ -245,12 +241,14 @@ export const BuyPlan = (props: {
|
||||
}
|
||||
onPress={async () => {
|
||||
if (isGithubRelease) {
|
||||
setCheckoutUrl(
|
||||
await db.subscriptions.checkoutUrl(
|
||||
(pricingPlans.selectedProduct as Plan).plan,
|
||||
(pricingPlans.selectedProduct as Plan).period
|
||||
)
|
||||
const url = await db.subscriptions.checkoutUrl(
|
||||
(pricingPlans.selectedProduct as Plan).plan,
|
||||
(pricingPlans.selectedProduct as Plan).period
|
||||
);
|
||||
if (url) {
|
||||
setCheckoutUrl(url);
|
||||
Linking.openURL(url);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -15,6 +15,7 @@ import {
|
||||
} from "../../../services/event-manager";
|
||||
import Navigation from "../../../services/navigation";
|
||||
import PremiumService from "../../../services/premium";
|
||||
import SettingsService from "../../../services/settings";
|
||||
import { useUserStore } from "../../../stores/use-user-store";
|
||||
import { eCloseSheet } from "../../../utils/events";
|
||||
import { AppFontSize } from "../../../utils/size";
|
||||
@@ -37,7 +38,6 @@ export default function PaywallSheet<Tid extends FeatureId>(props: {
|
||||
const { colors } = useThemeColors();
|
||||
const pricingPlans = usePricingPlans();
|
||||
useEffect(() => {
|
||||
console.log("PaywallSheet mounted with feature:", props.feature);
|
||||
ToastManager.hide();
|
||||
if (!props.feature.availableOn) return;
|
||||
const plan = pricingPlans.pricingPlans.find(
|
||||
@@ -55,11 +55,11 @@ export default function PaywallSheet<Tid extends FeatureId>(props: {
|
||||
}, []);
|
||||
|
||||
const isSubscribedOnWeb =
|
||||
(PremiumService.get() &&
|
||||
PremiumService.get() &&
|
||||
(pricingPlans.user?.subscription?.provider ===
|
||||
SubscriptionProvider.PADDLE ||
|
||||
pricingPlans.user?.subscription?.provider ===
|
||||
SubscriptionProvider.PADDLE) ||
|
||||
pricingPlans.user?.subscription?.provider ===
|
||||
SubscriptionProvider.STREETWRITERS;
|
||||
SubscriptionProvider.STREETWRITERS);
|
||||
|
||||
const isCurrentPlatform =
|
||||
(pricingPlans.user?.subscription?.provider === SubscriptionProvider.APPLE &&
|
||||
@@ -194,25 +194,28 @@ export default function PaywallSheet<Tid extends FeatureId>(props: {
|
||||
width: "100%"
|
||||
}}
|
||||
onPress={() => {
|
||||
if (
|
||||
pricingPlans.user?.subscription.plan ===
|
||||
SubscriptionPlan.LEGACY_PRO ||
|
||||
!isCurrentPlatform
|
||||
) {
|
||||
ToastManager.show({
|
||||
message: strings.cannotChangePlan(),
|
||||
context: "local"
|
||||
});
|
||||
return;
|
||||
if (PremiumService.get()) {
|
||||
if (
|
||||
pricingPlans.user?.subscription.plan ===
|
||||
SubscriptionPlan.LEGACY_PRO ||
|
||||
!isCurrentPlatform
|
||||
) {
|
||||
ToastManager.show({
|
||||
message: strings.cannotChangePlan(),
|
||||
context: "local"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (isSubscribedOnWeb) {
|
||||
ToastManager.show({
|
||||
message: strings.changePlanOnWeb(),
|
||||
context: "local"
|
||||
});
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
if (isSubscribedOnWeb) {
|
||||
ToastManager.show({
|
||||
message: strings.changePlanOnWeb(),
|
||||
context: "local"
|
||||
});
|
||||
return;
|
||||
}
|
||||
eSendEvent(eCloseSheet);
|
||||
if (!useUserStore.getState().user) {
|
||||
Navigation.navigate("Auth", {
|
||||
@@ -256,6 +259,7 @@ export default function PaywallSheet<Tid extends FeatureId>(props: {
|
||||
}
|
||||
|
||||
PaywallSheet.present = <Tid extends FeatureId>(feature: FeatureResult<Tid>) => {
|
||||
if (SettingsService.getProperty("serverUrls")) return;
|
||||
presentSheet({
|
||||
component: <PaywallSheet feature={feature} />
|
||||
});
|
||||
|
||||
@@ -20,6 +20,7 @@ import Paragraph from "../../ui/typography/paragraph";
|
||||
import { SubscriptionPlan, SubscriptionProvider } from "@notesnook/core";
|
||||
import { useUserStore } from "../../../stores/use-user-store";
|
||||
import PremiumService from "../../../services/premium";
|
||||
import SettingsService from "../../../services/settings";
|
||||
|
||||
export function PlanLimits() {
|
||||
const { colors } = useThemeColors();
|
||||
@@ -84,10 +85,11 @@ export function PlanLimits() {
|
||||
</View>
|
||||
))}
|
||||
|
||||
{(user?.subscription?.provider === SubscriptionProvider.PADDLE ||
|
||||
{((user?.subscription?.provider === SubscriptionProvider.PADDLE ||
|
||||
user?.subscription?.provider === SubscriptionProvider.STREETWRITERS ||
|
||||
!isCurrentPlatform) &&
|
||||
PremiumService.get() ? null : (
|
||||
PremiumService.get()) ||
|
||||
SettingsService.getProperty("serverUrls") ? null : (
|
||||
<Button
|
||||
title={strings.changePlan()}
|
||||
onPress={() => {
|
||||
|
||||
@@ -24,10 +24,11 @@ import { FlatList, View } from "react-native";
|
||||
import { DraxProvider, DraxScrollView } from "react-native-drax";
|
||||
import { db } from "../../common/database";
|
||||
import Navigation from "../../services/navigation";
|
||||
import SettingsService from "../../services/settings";
|
||||
import { useMenuStore } from "../../stores/use-menu-store";
|
||||
import { useSettingStore } from "../../stores/use-setting-store";
|
||||
import { useUserStore } from "../../stores/use-user-store";
|
||||
import { SUBSCRIPTION_STATUS } from "../../utils/constants";
|
||||
import { MenuItemsList } from "../../utils/menu-items";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import ReorderableList from "../list/reorderable-list";
|
||||
import { MenuItemProperties } from "../sheets/menu-item-properties";
|
||||
@@ -36,7 +37,6 @@ import { ColorSection } from "./color-section";
|
||||
import { MenuItem } from "./menu-item";
|
||||
import { PinnedSection } from "./pinned-section";
|
||||
import { SideMenuHeader } from "./side-menu-header";
|
||||
import { MenuItemsList } from "../../utils/menu-items";
|
||||
|
||||
const pro = {
|
||||
title: strings.upgradePlan(),
|
||||
@@ -140,9 +140,10 @@ export function SideMenuHome() {
|
||||
paddingVertical: DefaultAppStyles.GAP_VERTICAL
|
||||
}}
|
||||
>
|
||||
{subscriptionType === SubscriptionPlan.FREE ||
|
||||
!subscriptionType ||
|
||||
!user ? (
|
||||
{(subscriptionType === SubscriptionPlan.FREE ||
|
||||
!subscriptionType ||
|
||||
!user) &&
|
||||
!SettingsService.getProperty("serverUrls") ? (
|
||||
<Button
|
||||
title={pro.title}
|
||||
style={{
|
||||
|
||||
@@ -85,6 +85,7 @@ export default function useFeatureManager() {
|
||||
negativeText: strings.cancel(),
|
||||
positivePress: async () => {
|
||||
eSendEvent(eCloseSimpleDialog);
|
||||
if (SettingsService.getProperty("serverUrls")) return;
|
||||
Navigation.navigate("PayWall", {
|
||||
context: "logged-in"
|
||||
});
|
||||
|
||||
@@ -25,6 +25,7 @@ import { DatabaseLogger, db } from "../common/database";
|
||||
import PremiumService from "../services/premium";
|
||||
import { useSettingStore } from "../stores/use-setting-store";
|
||||
import { useUserStore } from "../stores/use-user-store";
|
||||
import SettingsService from "../services/settings";
|
||||
function numberWithCommas(x: string) {
|
||||
const parts = x.toString().split(".");
|
||||
parts[0] = parts[0].replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
@@ -201,7 +202,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
if (productId?.includes("5year")) return false;
|
||||
if (isGithubRelease) {
|
||||
if (
|
||||
user?.subscription.trialsAvailed?.some(
|
||||
user?.subscription?.trialsAvailed?.some(
|
||||
(plan) => plan === planIdToIndex(planId || currentPlan)
|
||||
)
|
||||
) {
|
||||
@@ -246,7 +247,10 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
});
|
||||
setPlans([...pricingPlans]);
|
||||
setUserCanRequestTrial(hasTrialOffer());
|
||||
if (Config.GITHUB_RELEASE === "true") {
|
||||
if (
|
||||
Config.GITHUB_RELEASE === "true" &&
|
||||
!SettingsService.getProperty("serverUrls")
|
||||
) {
|
||||
try {
|
||||
const products = WebPlanCache || (await db.pricing.products());
|
||||
WebPlanCache = products;
|
||||
@@ -264,7 +268,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
if (!product) return;
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
if (isGithubRelease)
|
||||
if (isGithubRelease) {
|
||||
if (!(product as Plan)?.price) return null;
|
||||
return `${(product as Plan).price.currency} ${
|
||||
(product as Plan).period === "yearly"
|
||||
? ((product as Plan).price.gross / 12).toFixed(2)
|
||||
@@ -272,6 +277,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
? ((product as Plan).price.gross / (12 * 5)).toFixed(2)
|
||||
: (product as Plan).price.gross
|
||||
}`;
|
||||
}
|
||||
|
||||
const pricingPhaseListItem =
|
||||
(product as RNIap.SubscriptionAndroid)?.subscriptionOfferDetails?.[0]
|
||||
@@ -414,7 +420,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
offerIndex: number
|
||||
) => {
|
||||
if (isGithubRelease) {
|
||||
return (product as Plan).period;
|
||||
return (product as Plan)?.period;
|
||||
}
|
||||
|
||||
if (Platform.OS === "android") {
|
||||
@@ -444,7 +450,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
if (isGithubRelease) {
|
||||
return {
|
||||
duration: 1,
|
||||
type: (product as Plan).period
|
||||
type: (product as Plan)?.period
|
||||
};
|
||||
}
|
||||
|
||||
@@ -591,7 +597,8 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
) => {
|
||||
if (!product) return null;
|
||||
|
||||
if (isGithubRelease)
|
||||
if (isGithubRelease) {
|
||||
if (!(product as Plan)?.price) return null;
|
||||
return `${(product as Plan).price.currency} ${
|
||||
(product as Plan).period === "yearly"
|
||||
? ((product as Plan).price.gross / 12).toFixed(2)
|
||||
@@ -599,6 +606,7 @@ const usePricingPlans = (options?: PricingPlansOptions) => {
|
||||
? ((product as Plan).price.gross / (12 * 5)).toFixed(2)
|
||||
: (product as Plan).price.gross
|
||||
}`;
|
||||
}
|
||||
|
||||
const androidPricingPhase = (product as RNIap.SubscriptionAndroid)
|
||||
?.subscriptionOfferDetails?.[0].pricingPhases?.pricingPhaseList?.[
|
||||
|
||||
@@ -43,6 +43,7 @@ import { planToDisplayName } from "../../utils/constants";
|
||||
import { AppFontSize } from "../../utils/size";
|
||||
import { DefaultAppStyles } from "../../utils/styles";
|
||||
import { SectionItem } from "./section-item";
|
||||
import SettingsService from "../../services/settings";
|
||||
|
||||
export const getTimeLeft = (t2) => {
|
||||
let daysRemaining = dayjs(t2).diff(dayjs(), "days");
|
||||
@@ -339,11 +340,13 @@ const SettingsUserSection = ({ item }) => {
|
||||
</Paragraph>
|
||||
</TouchableOpacity>
|
||||
|
||||
{(user.subscription?.provider === SubscriptionProvider.PADDLE ||
|
||||
{((user.subscription?.provider ===
|
||||
SubscriptionProvider.PADDLE ||
|
||||
user.subscription?.provider ===
|
||||
SubscriptionProvider.STREETWRITERS ||
|
||||
!isCurrentPlatform) &&
|
||||
PremiumService.get() ? null : (
|
||||
PremiumService.get()) ||
|
||||
SettingsService.getProperty("serverUrls") ? null : (
|
||||
<Button
|
||||
title={
|
||||
user.subscription?.plan !== SubscriptionPlan.FREE
|
||||
|
||||
@@ -71,6 +71,7 @@ export function planToDisplayName(plan: SubscriptionPlan): string {
|
||||
return strings.freePlan();
|
||||
case SubscriptionPlan.ESSENTIAL:
|
||||
return strings.essentialPlan();
|
||||
case SubscriptionPlan.LEGACY_PRO:
|
||||
case SubscriptionPlan.PRO:
|
||||
return strings.proPlan();
|
||||
case SubscriptionPlan.BELIEVER:
|
||||
|
||||
@@ -18,7 +18,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { authenticator } from "otplib";
|
||||
import { Tests } from "./utils";
|
||||
import { TestBuilder } from "./utils";
|
||||
|
||||
import dotenv from "dotenv";
|
||||
import path from "path";
|
||||
@@ -34,20 +34,6 @@ const USER = {
|
||||
}
|
||||
};
|
||||
|
||||
async function login() {
|
||||
await Tests.fromText("Login to encrypt and sync notes").tap();
|
||||
await Tests.fromId("input.email").element.typeText(USER.login.email!);
|
||||
await Tests.fromText("Continue").tap();
|
||||
await Tests.sleep(3000);
|
||||
await Tests.fromId("input.totp").element.typeText(
|
||||
authenticator.generate(USER.login.totpSecret!)
|
||||
);
|
||||
await Tests.fromText("Next").tap();
|
||||
await Tests.sleep(3000);
|
||||
await Tests.fromId("input.password").element.typeText(USER.login.password!);
|
||||
await Tests.fromId("input.password").element.tapReturnKey();
|
||||
}
|
||||
|
||||
// async function deleteAccount() {
|
||||
// await tapByText("Account Settings");
|
||||
// await sleep(2000);
|
||||
@@ -67,11 +53,27 @@ async function login() {
|
||||
// await elementById("input.confirmPassword").tapReturnKey();
|
||||
// }
|
||||
|
||||
async function login() {
|
||||
await TestBuilder.create()
|
||||
.waitAndTapByText("Login to encrypt and sync notes")
|
||||
.typeTextById("input.email", USER.login.email!)
|
||||
.tapReturnKeyById("input.email")
|
||||
.wait(3000)
|
||||
.typeTextById("input.totp", authenticator.generate(USER.login.totpSecret!))
|
||||
.waitAndTapByText("Next")
|
||||
.wait(3000)
|
||||
.typeTextById("input.password", USER.login.password!)
|
||||
.tapReturnKeyById("input.password")
|
||||
.run();
|
||||
}
|
||||
|
||||
describe("AUTH", () => {
|
||||
it("Login", async () => {
|
||||
await Tests.prepare();
|
||||
await login();
|
||||
await Tests.sleep(10000);
|
||||
await Tests.fromText("Login to encrypt and sync notes").isNotVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.addStep(login)
|
||||
.wait(3000)
|
||||
.isNotVisibleByText("Notesnook Plans")
|
||||
.run();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1,3 +1,22 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { notesnook } from "../test.ids";
|
||||
import { TestBuilder } from "./utils";
|
||||
|
||||
|
||||
@@ -18,266 +18,209 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { notesnook } from "../test.ids";
|
||||
import { Tests } from "./utils";
|
||||
import { TestBuilder } from "./utils";
|
||||
|
||||
describe("NOTEBOOKS", () => {
|
||||
it("Create a notebook with title only", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
await Tests.createNotebook("Notebook 1", false);
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", false)
|
||||
.wait(500)
|
||||
.isVisibleByText("Notebook 1")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Create a notebook title & description", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
await Tests.createNotebook("Notebook 1", true);
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
it("Create a notebook with title & description", async () => {
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", true)
|
||||
.wait(500)
|
||||
.isVisibleByText("Notebook 1")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Add a sub notebook to a notebook", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
await Tests.createNotebook("Notebook 1", true);
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Notebook 1").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Add notebook").waitAndTap();
|
||||
await Tests.createNotebook("Sub notebook", true);
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId("expand-notebook-0").waitAndTap();
|
||||
await Tests.fromText("Sub notebook").isVisible();
|
||||
await Tests.fromText("Sub notebook").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Move to trash").waitAndTap();
|
||||
await Tests.fromText("Delete").waitAndTap();
|
||||
await Tests.fromText("Sub notebook").isNotVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", true)
|
||||
.wait(500)
|
||||
.longPressByText("Notebook 1")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Add notebook")
|
||||
.createNotebook("Sub notebook", true)
|
||||
.wait(500)
|
||||
.waitAndTapById("expand-notebook-0")
|
||||
.isVisibleByText("Sub notebook")
|
||||
.longPressByText("Sub notebook")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Move to trash")
|
||||
.waitAndTapByText("Delete")
|
||||
.isNotVisibleByText("Sub notebook")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Edit notebook", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
await Tests.createNotebook("Notebook 1", true);
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Notebook 1").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Edit notebook").waitAndTap();
|
||||
await Tests.fromId(
|
||||
notesnook.ids.dialogs.notebook.inputs.title
|
||||
).element.typeText(" (edited)");
|
||||
await Tests.fromText("Save").waitAndTap();
|
||||
await Tests.fromText("Notebook 1 (edited)").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", true)
|
||||
.wait(500)
|
||||
.longPressByText("Notebook 1")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Edit notebook")
|
||||
.typeTextById(notesnook.ids.dialogs.notebook.inputs.title, " (edited)")
|
||||
.waitAndTapByText("Save")
|
||||
.isVisibleByText("Notebook 1 (edited)")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Edit a sub notebook", async () => {
|
||||
await Tests.prepare();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
await Tests.createNotebook("Notebook 1", true);
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromText("Notebook 1").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Add notebook").waitAndTap();
|
||||
|
||||
await Tests.createNotebook("Sub notebook", true);
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromId("expand-notebook-0").waitAndTap();
|
||||
await Tests.fromText("Sub notebook").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Edit notebook").waitAndTap();
|
||||
await Tests.fromId(
|
||||
notesnook.ids.dialogs.notebook.inputs.title
|
||||
).element.typeText(" (edited)");
|
||||
await Tests.fromText("Save").waitAndTap();
|
||||
await Tests.fromText("Sub notebook (edited)").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", true)
|
||||
.wait(500)
|
||||
.longPressByText("Notebook 1")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Add notebook")
|
||||
.createNotebook("Sub notebook", true)
|
||||
.wait(500)
|
||||
.waitAndTapById("expand-notebook-0")
|
||||
.longPressByText("Sub notebook")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Edit notebook")
|
||||
.typeTextById(notesnook.ids.dialogs.notebook.inputs.title, " (edited)")
|
||||
.waitAndTapByText("Save")
|
||||
.isVisibleByText("Sub notebook (edited)")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Add a note to notebook", async () => {
|
||||
await Tests.prepare();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.createNotebook("Notebook 1", true);
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromText("Notebook 1").waitAndTap();
|
||||
await Tests.createNote();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", true)
|
||||
.wait(500)
|
||||
.waitAndTapByText("Notebook 1")
|
||||
.createNote()
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Remove note from Notebook", async () => {
|
||||
await Tests.prepare();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.createNotebook("Notebook 1", true);
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromText("Notebook 1").waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
let note = await Tests.createNote();
|
||||
await Tests.fromText(note.body).element.longPress();
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromId("select-minus").waitAndTap();
|
||||
await Tests.fromId(note.title).isNotVisible();
|
||||
it.only("Remove note from notebook", async () => {
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", true)
|
||||
.wait(500)
|
||||
.waitAndTapByText("Notebook 1")
|
||||
.wait(500)
|
||||
.createNote()
|
||||
.saveResult()
|
||||
.processResult(async (note) => {
|
||||
await TestBuilder.create()
|
||||
.longPressByText(note.body)
|
||||
.wait(500)
|
||||
.waitAndTapById("select-minus")
|
||||
.isNotVisibleById(note.title)
|
||||
.run();
|
||||
})
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Add/Remove note to notebook from home", async () => {
|
||||
await Tests.prepare();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.createNotebook("Notebook 1", true);
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId("tab-home").waitAndTap();
|
||||
|
||||
await Tests.fromText("Notes").waitAndTap();
|
||||
await Tests.createNote();
|
||||
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromId("icon-notebooks").waitAndTap();
|
||||
await Tests.fromText("Notebook 1").waitAndTap();
|
||||
|
||||
await Tests.fromId("floating-save-button").waitAndTap();
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", true)
|
||||
.wait(500)
|
||||
.waitAndTapById("tab-home")
|
||||
.waitAndTapByText("Notes")
|
||||
.createNote()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.wait(500)
|
||||
.waitAndTapById("icon-notebooks")
|
||||
.waitAndTapByText("Notebook 1")
|
||||
.waitAndTapById("floating-save-button")
|
||||
.isVisibleByText("Notebook 1")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Edit notebook title, description", async () => {
|
||||
await Tests.prepare();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.createNotebook();
|
||||
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
|
||||
await Tests.fromText("Notebook 1").element.longPress();
|
||||
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Edit notebook").waitAndTap();
|
||||
await Tests.fromId(
|
||||
notesnook.ids.dialogs.notebook.inputs.title
|
||||
).element.typeText(" (Edited)");
|
||||
await Tests.fromId(
|
||||
notesnook.ids.dialogs.notebook.inputs.description
|
||||
).element.clearText();
|
||||
await Tests.fromId(
|
||||
notesnook.ids.dialogs.notebook.inputs.description
|
||||
).element.typeText("Description of Notebook 1 (Edited)");
|
||||
await Tests.fromText("Save").waitAndTap();
|
||||
await Tests.fromText("Notebook 1 (Edited)").isVisible();
|
||||
it("Edit notebook title and description", async () => {
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook()
|
||||
.wait(500)
|
||||
.isVisibleByText("Notebook 1")
|
||||
.longPressByText("Notebook 1")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Edit notebook")
|
||||
.typeTextById(notesnook.ids.dialogs.notebook.inputs.title, " (Edited)")
|
||||
.clearTextById(notesnook.ids.dialogs.notebook.inputs.description)
|
||||
.typeTextById(
|
||||
notesnook.ids.dialogs.notebook.inputs.description,
|
||||
"Description of Notebook 1 (Edited)"
|
||||
)
|
||||
.waitAndTapByText("Save")
|
||||
.isVisibleByText("Notebook 1 (Edited)")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Move notebook to trash", async () => {
|
||||
await Tests.prepare();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.createNotebook("Notebook 1", false);
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
|
||||
await Tests.fromText("Notebook 1").element.longPress();
|
||||
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Move to trash").waitAndTap();
|
||||
await Tests.fromText("Delete").waitAndTap();
|
||||
|
||||
await Tests.fromId("tab-home").waitAndTap();
|
||||
|
||||
await Tests.fromText("Trash").waitAndTap();
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
});
|
||||
|
||||
it.skip("Move notebook to trash with notes", async () => {
|
||||
await Tests.prepare();
|
||||
let note = await Tests.createNote();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.createNotebook("Notebook 1", false);
|
||||
await device.pressBack();
|
||||
await Tests.fromId(notesnook.ids.note.get(0)).element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId("select-plus").waitAndTap();
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
await Tests.fromText("Notebook 1").waitAndTap();
|
||||
await Tests.fromId("floating-save-button").waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-home").waitAndTap();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
await Tests.fromText("Notebook 1").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Move to trash").waitAndTap();
|
||||
await Tests.fromText(
|
||||
"Move all notes in this notebook to trash"
|
||||
).waitAndTap();
|
||||
await Tests.fromText("Delete").waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId("tab-home").waitAndTap();
|
||||
|
||||
await Tests.fromText("Trash").waitAndTap();
|
||||
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
await Tests.fromText(note.body).isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", false)
|
||||
.wait(500)
|
||||
.isVisibleByText("Notebook 1")
|
||||
.longPressByText("Notebook 1")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Move to trash")
|
||||
.waitAndTapByText("Delete")
|
||||
.waitAndTapById("tab-home")
|
||||
.waitAndTapByText("Trash")
|
||||
.isVisibleByText("Notebook 1")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Pin notebook to side menu", async () => {
|
||||
await Tests.prepare();
|
||||
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-notebooks").waitAndTap();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.createNotebook("Notebook 1", false);
|
||||
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
|
||||
await Tests.fromText("Notebook 1").element.longPress();
|
||||
|
||||
await Tests.sleep(500);
|
||||
|
||||
await Tests.fromId("icon-add-shortcut").waitAndTap();
|
||||
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId("tab-home").waitAndTap();
|
||||
|
||||
await Tests.fromText("Notebook 1").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-notebooks")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.createNotebook("Notebook 1", false)
|
||||
.wait(500)
|
||||
.isVisibleByText("Notebook 1")
|
||||
.longPressByText("Notebook 1")
|
||||
.wait(500)
|
||||
.waitAndTapById("icon-add-shortcut")
|
||||
.wait(500)
|
||||
.waitAndTapById("tab-home")
|
||||
.isVisibleByText("Notebook 1")
|
||||
.run();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -17,15 +17,17 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { Tests } from "./utils";
|
||||
import { TestBuilder } from "./utils";
|
||||
|
||||
describe("Search", () => {
|
||||
it("Search for a note", async () => {
|
||||
await Tests.prepare();
|
||||
let note = await Tests.createNote();
|
||||
await Tests.fromId("search-header").waitAndTap();
|
||||
await Tests.fromId("search-input").element.typeText("Test");
|
||||
await Tests.sleep(1000);
|
||||
await Tests.fromText("1").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.waitAndTapById("search-header")
|
||||
.typeTextById("search-input", "Test")
|
||||
.wait(1000)
|
||||
.isVisibleByText("1")
|
||||
.run();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,74 +18,99 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { notesnook } from "../test.ids";
|
||||
import { Tests } from "./utils";
|
||||
|
||||
async function sortBy(sorting: string) {
|
||||
await Tests.fromId("icon-sort").waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText(sorting).waitAndTap();
|
||||
await device.pressBack();
|
||||
}
|
||||
import { TestBuilder } from "./utils";
|
||||
|
||||
describe("Sort & filter", () => {
|
||||
it("Sort by date-edited/date-created", async () => {
|
||||
await Tests.prepare();
|
||||
let webview = web();
|
||||
await Tests.createNote("Note 1", "Note 1");
|
||||
await Tests.createNote("Note 2", "Note 2");
|
||||
await Tests.fromText("Note 1").waitAndTap();
|
||||
await webview.element(by.web.className("ProseMirror")).tap();
|
||||
await webview
|
||||
.element(by.web.className("ProseMirror"))
|
||||
.typeText("Edited ", true);
|
||||
await device.pressBack();
|
||||
await sortBy("Date created");
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await device.pressBack();
|
||||
await sortBy("Date edited");
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await device.pressBack();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
.createNote("Note 2", "Note 2")
|
||||
.waitAndTapByText("Note 1")
|
||||
.addStep(async () => {
|
||||
const webview = web();
|
||||
await webview.element(by.web.className("ProseMirror")).tap();
|
||||
await webview
|
||||
.element(by.web.className("ProseMirror"))
|
||||
.typeText("Edited ", true);
|
||||
})
|
||||
.pressBack()
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Date created")
|
||||
.pressBack()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.pressBack()
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Date edited")
|
||||
.pressBack()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Disable grouping", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote("Note 1", "Note 1");
|
||||
await sortBy("None");
|
||||
await Tests.fromText("ALL").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("None")
|
||||
.pressBack()
|
||||
.isVisibleByText("ALL")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Group by Abc", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote("Note 1", "Note 1");
|
||||
await sortBy("Abc");
|
||||
await Tests.fromText("N").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Abc")
|
||||
.pressBack()
|
||||
.isVisibleByText("N")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Group by Year", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote("Note 1", "Note 1");
|
||||
await sortBy("Year");
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Year")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Group by Week", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote("Note 1", "Note 1");
|
||||
await sortBy("Week");
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Week")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Group by Month", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote("Note 1", "Note 1");
|
||||
await sortBy("Month");
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
.waitAndTapById("icon-sort")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Month")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Compact mode", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote("Note 1", "Note 1");
|
||||
await Tests.fromId("icon-compact-mode").waitAndTap();
|
||||
await Tests.fromText("Note 1").isNotVisible();
|
||||
await Tests.fromId("icon-compact-mode").waitAndTap();
|
||||
await Tests.fromText("Note 1").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote("Note 1", "Note 1")
|
||||
.waitAndTapById("icon-compact-mode")
|
||||
.isNotVisibleByText("Note 1")
|
||||
.waitAndTapById("icon-compact-mode")
|
||||
.isVisibleByText("Note 1")
|
||||
.run();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -18,95 +18,101 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { notesnook } from "../test.ids";
|
||||
import { Tests } from "./utils";
|
||||
import { TestBuilder } from "./utils";
|
||||
|
||||
describe("Tags", () => {
|
||||
it("Create a tag", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-tags").waitAndTap();
|
||||
|
||||
await Tests.fromText("No tags").isVisible();
|
||||
await Tests.fromId("sidebar-add-button").waitAndTap();
|
||||
|
||||
await Tests.fromId("input-value").element.typeText("testtag");
|
||||
|
||||
await Tests.fromText("Add").waitAndTap();
|
||||
await Tests.fromText("testtag").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-tags")
|
||||
.isVisibleByText("No tags")
|
||||
.waitAndTapById("sidebar-add-button")
|
||||
.typeTextById("input-value", "testtag")
|
||||
.waitAndTapByText("Add")
|
||||
.isVisibleByText("testtag")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Tag a note", async () => {
|
||||
await Tests.prepare();
|
||||
let note = await Tests.createNote();
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Add tag").waitAndTap();
|
||||
await Tests.fromId("tag-input").element.typeText("testtag");
|
||||
await Tests.fromText('Add "#testtag"').waitAndTap();
|
||||
await Tests.fromText("#testtag").isVisible();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-tags").waitAndTap();
|
||||
await Tests.fromText("#testtag").waitAndTap();
|
||||
await Tests.fromText(note.body).isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.saveResult()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.wait(500)
|
||||
.waitAndTapByText("Add tag")
|
||||
.typeTextById("tag-input", "testtag")
|
||||
.waitAndTapByText('Add "#testtag"')
|
||||
.isVisibleByText("#testtag")
|
||||
.pressBack(2)
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-tags")
|
||||
.waitAndTapByText("#testtag")
|
||||
.processResult(async (note) => {
|
||||
await TestBuilder.create().isVisibleByText(note.body).run();
|
||||
})
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Untag a note", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Add tag").waitAndTap();
|
||||
await Tests.fromId("tag-input").element.typeText("testtag");
|
||||
await Tests.fromText('Add "#testtag"').waitAndTap();
|
||||
await Tests.fromText("#testtag").isVisible();
|
||||
await Tests.fromText("#testtag").waitAndTap();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await Tests.fromText("#testtag").isNotVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.wait(500)
|
||||
.waitAndTapByText("Add tag")
|
||||
.typeTextById("tag-input", "testtag")
|
||||
.waitAndTapByText('Add "#testtag"')
|
||||
.isVisibleByText("#testtag")
|
||||
.waitAndTapByText("#testtag")
|
||||
.pressBack(2)
|
||||
.isNotVisibleByText("#testtag")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Create shortcut of a tag", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Add tag").waitAndTap();
|
||||
await Tests.fromId("tag-input").element.typeText("testtag");
|
||||
await Tests.fromText('Add "#testtag"').waitAndTap();
|
||||
await Tests.fromText("#testtag").isVisible();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-tags").waitAndTap();
|
||||
await Tests.fromText("testtag").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Add shortcut").waitAndTap();
|
||||
await Tests.fromId("tab-home").waitAndTap();
|
||||
await Tests.fromText("testtag").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.wait(500)
|
||||
.waitAndTapByText("Add tag")
|
||||
.typeTextById("tag-input", "testtag")
|
||||
.waitAndTapByText('Add "#testtag"')
|
||||
.isVisibleByText("#testtag")
|
||||
.pressBack(2)
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-tags")
|
||||
.longPressByText("testtag")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Add shortcut")
|
||||
.waitAndTapById("tab-home")
|
||||
.isVisibleByText("testtag")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Rename a tag", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Add tag").waitAndTap();
|
||||
await Tests.fromId("tag-input").element.typeText("testtag");
|
||||
await Tests.fromText('Add "#testtag"').waitAndTap();
|
||||
await Tests.fromText("#testtag").isVisible();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("tab-tags").waitAndTap();
|
||||
await Tests.fromText("testtag").element.longPress();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Rename").waitAndTap();
|
||||
await Tests.sleep(100);
|
||||
await Tests.fromId("input-value").element.clearText();
|
||||
await Tests.fromId("input-value").element.typeText("testtag_edited");
|
||||
await Tests.fromText("Save").waitAndTap();
|
||||
await Tests.fromText("testtag_edited").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.wait(500)
|
||||
.waitAndTapByText("Add tag")
|
||||
.typeTextById("tag-input", "testtag")
|
||||
.waitAndTapByText('Add "#testtag"')
|
||||
.isVisibleByText("#testtag")
|
||||
.pressBack(2)
|
||||
.openSideMenu()
|
||||
.waitAndTapById("tab-tags")
|
||||
.longPressByText("testtag")
|
||||
.wait(500)
|
||||
.waitAndTapByText("Rename")
|
||||
.wait(100)
|
||||
.clearTextById("input-value")
|
||||
.typeTextById("input-value", "testtag_edited")
|
||||
.waitAndTapByText("Save")
|
||||
.isVisibleByText("testtag_edited")
|
||||
.run();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -171,7 +171,7 @@ class TestBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
wait(duration: number) {
|
||||
wait(duration = 500) {
|
||||
return this.addStep(async () => {
|
||||
await Tests.sleep(duration);
|
||||
});
|
||||
@@ -280,6 +280,13 @@ class TestBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
tapReturnKeyById(id: string) {
|
||||
return this.addStep(async () => {
|
||||
const element = new Element("id", id);
|
||||
await element.element.tapReturnKey();
|
||||
});
|
||||
}
|
||||
|
||||
tapByText(text: string, point?: Detox.Point2D) {
|
||||
return this.addStep(async () => {
|
||||
const element = new Element("text", text);
|
||||
@@ -303,6 +310,12 @@ class TestBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
clearTextById(id: string) {
|
||||
return this.addStep(async () => {
|
||||
await Element.fromId(id).element.clearText();
|
||||
});
|
||||
}
|
||||
|
||||
pressBack(count = 1) {
|
||||
return this.addStep(async () => {
|
||||
for (let i = 0; i < count; i++) {
|
||||
@@ -311,6 +324,20 @@ class TestBuilder {
|
||||
});
|
||||
}
|
||||
|
||||
longPressByText(text: string) {
|
||||
return this.addStep(async () => {
|
||||
const element = new Element("text", text);
|
||||
await element.element.longPress();
|
||||
});
|
||||
}
|
||||
|
||||
longPressById(id: string) {
|
||||
return this.addStep(async () => {
|
||||
const element = new Element("id", id);
|
||||
await element.element.longPress();
|
||||
});
|
||||
}
|
||||
|
||||
async run() {
|
||||
for (const step of this.steps) {
|
||||
const result = step.call(this);
|
||||
|
||||
@@ -18,134 +18,133 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { expect } from "detox";
|
||||
import { notesnook } from "../test.ids";
|
||||
import { Tests } from "./utils";
|
||||
import { TestBuilder, Tests } from "./utils";
|
||||
|
||||
async function lockNote() {
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId("icon-lock-unlock").waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromText("Lock").isVisible();
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwd).element.typeText("1234");
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwdAlt).element.typeText(
|
||||
"1234"
|
||||
);
|
||||
await Tests.fromText("Lock").waitAndTap();
|
||||
await Tests.fromId("note-locked-icon").isVisible();
|
||||
await TestBuilder.create()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.wait()
|
||||
.waitAndTapById("icon-lock-unlock")
|
||||
.wait()
|
||||
.isVisibleByText("Lock")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwdAlt, "1234")
|
||||
.waitAndTapByText("Lock")
|
||||
.isVisibleById("note-locked-icon")
|
||||
.run();
|
||||
}
|
||||
|
||||
async function removeFromVault() {
|
||||
await Tests.fromId(notesnook.listitem.menu).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId("icon-lock-unlock").waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwd).element.typeText("1234");
|
||||
await Tests.fromText("Unlock").waitAndTap();
|
||||
await Tests.fromId("note-locked-icon").isNotVisible();
|
||||
await TestBuilder.create()
|
||||
.waitAndTapById(notesnook.listitem.menu)
|
||||
.wait()
|
||||
.waitAndTapById("icon-lock-unlock")
|
||||
.wait()
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
|
||||
.waitAndTapByText("Unlock")
|
||||
.isNotVisibleById("note-locked-icon")
|
||||
.run();
|
||||
}
|
||||
|
||||
async function openLockedNote(pwd?: string) {
|
||||
await Tests.fromId(notesnook.ids.note.get(0)).waitAndTap();
|
||||
await Tests.sleep(500);
|
||||
await web()
|
||||
.element(by.web.name("password"))
|
||||
.typeText(pwd || "1234", false);
|
||||
await web().element(by.web.className("unlock-note")).tap();
|
||||
await Tests.sleep(500);
|
||||
await expect(web().element(by.web.className("unlock-note"))).not.toExist();
|
||||
async function openLockedNote(pwd = "1234") {
|
||||
await TestBuilder.create()
|
||||
.waitAndTapById(notesnook.ids.note.get(0))
|
||||
.wait()
|
||||
.addStep(async () => {
|
||||
await web().element(by.web.name("password")).typeText(pwd, false);
|
||||
await web().element(by.web.className("unlock-note")).tap();
|
||||
await Tests.sleep(500);
|
||||
await expect(
|
||||
web().element(by.web.className("unlock-note"))
|
||||
).not.toExist();
|
||||
})
|
||||
.run();
|
||||
}
|
||||
|
||||
async function goToPrivacySecuritySettings() {
|
||||
await Tests.openSideMenu();
|
||||
await Tests.fromId("sidemenu-settings-icon").waitAndTap();
|
||||
await Tests.sleep(300);
|
||||
await Tests.fromText("Settings").waitAndTap();
|
||||
await Tests.fromText("Vault").waitAndTap();
|
||||
await TestBuilder.create()
|
||||
.openSideMenu()
|
||||
.waitAndTapById("sidemenu-settings-icon")
|
||||
.wait()
|
||||
.waitAndTapByText("Settings")
|
||||
.waitAndTapByText("Vault")
|
||||
.run();
|
||||
}
|
||||
|
||||
describe("VAULT", () => {
|
||||
it("Create vault from settings", async () => {
|
||||
await Tests.prepare();
|
||||
await goToPrivacySecuritySettings();
|
||||
await Tests.fromText("Create vault").waitAndTap();
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwd).element.typeText(
|
||||
"1234"
|
||||
);
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwdAlt).element.typeText(
|
||||
"1234"
|
||||
);
|
||||
await Tests.fromText("Create").waitAndTap();
|
||||
await Tests.fromText("Clear vault").isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.addStep(goToPrivacySecuritySettings)
|
||||
.waitAndTapByText("Create vault")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwdAlt, "1234")
|
||||
.waitAndTapByText("Create")
|
||||
.isVisibleByText("Clear vault")
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Change vault password", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await lockNote();
|
||||
await goToPrivacySecuritySettings();
|
||||
await Tests.fromText("Change vault password").waitAndTap();
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwd).element.typeText(
|
||||
"1234"
|
||||
);
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.changePwd).element.typeText(
|
||||
"2362"
|
||||
);
|
||||
await Tests.fromText("Change").waitAndTap();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await Tests.sleep(500);
|
||||
await openLockedNote("2362");
|
||||
it.only("Change vault password", async () => {
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.addStep(lockNote)
|
||||
.addStep(goToPrivacySecuritySettings)
|
||||
.waitAndTapByText("Change vault password")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.changePwd, "2362")
|
||||
.waitAndTapByText("Change")
|
||||
.pressBack(3)
|
||||
.addStep(async () => await openLockedNote("2362"))
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Delete vault", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await lockNote();
|
||||
await goToPrivacySecuritySettings();
|
||||
await Tests.fromText("Delete vault").waitAndTap();
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwd).element.typeText(
|
||||
"1234"
|
||||
);
|
||||
await Tests.fromText("Delete").waitAndTap();
|
||||
await Tests.sleep(300);
|
||||
await Tests.fromText("Create vault").isVisible();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await Tests.fromId(notesnook.listitem.menu).isVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.addStep(lockNote)
|
||||
.addStep(goToPrivacySecuritySettings)
|
||||
.waitAndTapByText("Delete vault")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
|
||||
.waitAndTapByText("Delete")
|
||||
.isVisibleByText("Create vault")
|
||||
.pressBack(3)
|
||||
.isVisibleById(notesnook.listitem.menu)
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Delete vault with locked notes", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await lockNote();
|
||||
await goToPrivacySecuritySettings();
|
||||
await Tests.fromText("Delete vault").waitAndTap();
|
||||
await Tests.fromId(notesnook.ids.dialogs.vault.pwd).element.typeText(
|
||||
"1234"
|
||||
);
|
||||
await Tests.fromText("Delete notes in this vault").waitAndTap();
|
||||
await Tests.fromText("Delete").waitAndTap();
|
||||
await Tests.sleep(300);
|
||||
await Tests.fromText("Create vault").isVisible();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await device.pressBack();
|
||||
await Tests.fromId(notesnook.listitem.menu).isNotVisible();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.addStep(lockNote)
|
||||
.addStep(goToPrivacySecuritySettings)
|
||||
.waitAndTapByText("Delete vault")
|
||||
.typeTextById(notesnook.ids.dialogs.vault.pwd, "1234")
|
||||
.waitAndTapByText("Delete notes in this vault")
|
||||
.waitAndTapByText("Delete")
|
||||
.isVisibleByText("Create vault")
|
||||
.pressBack(3)
|
||||
.isNotVisibleById(notesnook.listitem.menu)
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Add a note to vault", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await lockNote();
|
||||
await openLockedNote();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.addStep(lockNote)
|
||||
.addStep(openLockedNote)
|
||||
.run();
|
||||
});
|
||||
|
||||
it("Remove note from vault", async () => {
|
||||
await Tests.prepare();
|
||||
await Tests.createNote();
|
||||
await lockNote();
|
||||
await removeFromVault();
|
||||
await TestBuilder.create()
|
||||
.prepare()
|
||||
.createNote()
|
||||
.addStep(lockNote)
|
||||
.addStep(removeFromVault)
|
||||
.run();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1 +1 @@
|
||||
GITHUB_RELEASE=false
|
||||
GITHUB_RELEASE=true
|
||||
@@ -124,7 +124,7 @@ android {
|
||||
minSdkVersion rootProject.ext.minSdkVersion
|
||||
targetSdkVersion rootProject.ext.targetSdkVersion
|
||||
multiDexEnabled true
|
||||
versionCode 3071
|
||||
versionCode 3072
|
||||
versionName getNpmVersion()
|
||||
testBuildType System.getProperty('testBuildType', 'debug')
|
||||
testInstrumentationRunner 'androidx.test.runner.AndroidJUnitRunner'
|
||||
|
||||
@@ -152,7 +152,7 @@
|
||||
<category android:name="android.intent.category.DEFAULT" />
|
||||
<category android:name="android.intent.category.BROWSABLE" />
|
||||
|
||||
<data android:scheme="com.streetwriters.notesnook" />
|
||||
<data android:scheme="notesnook" />
|
||||
</intent-filter>
|
||||
|
||||
</activity>
|
||||
|
||||
@@ -1089,7 +1089,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2150;
|
||||
CURRENT_PROJECT_VERSION = 2151;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
ENABLE_BITCODE = NO;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1163,7 +1163,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.2;
|
||||
MARKETING_VERSION = 3.3.3;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
"-ObjC",
|
||||
@@ -1194,7 +1194,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
CURRENT_PROJECT_VERSION = 2150;
|
||||
CURRENT_PROJECT_VERSION = 2151;
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1268,7 +1268,7 @@
|
||||
"$(inherited)",
|
||||
"@executable_path/Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.2;
|
||||
MARKETING_VERSION = 3.3.3;
|
||||
ONLY_ACTIVE_ARCH = NO;
|
||||
OTHER_LDFLAGS = (
|
||||
"$(inherited)",
|
||||
@@ -1427,7 +1427,7 @@
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2150;
|
||||
CURRENT_PROJECT_VERSION = 2151;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1439,7 +1439,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.2;
|
||||
MARKETING_VERSION = 3.3.3;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
@@ -1470,7 +1470,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2150;
|
||||
CURRENT_PROJECT_VERSION = 2151;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1483,7 +1483,7 @@
|
||||
"@executable_path/Frameworks",
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
MARKETING_VERSION = 3.3.2;
|
||||
MARKETING_VERSION = 3.3.3;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.notewidget;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
@@ -1513,7 +1513,7 @@
|
||||
CODE_SIGN_ENTITLEMENTS = "Make Note/Make Note.entitlements";
|
||||
CODE_SIGN_IDENTITY = "Apple Development";
|
||||
CODE_SIGN_STYLE = Automatic;
|
||||
CURRENT_PROJECT_VERSION = 2150;
|
||||
CURRENT_PROJECT_VERSION = 2151;
|
||||
DEBUG_INFORMATION_FORMAT = dwarf;
|
||||
DEVELOPMENT_TEAM = 53CWBG3QUC;
|
||||
"EXCLUDED_ARCHS[sdk=iphonesimulator*]" = arm64;
|
||||
@@ -1594,7 +1594,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
|
||||
MARKETING_VERSION = 3.3.2;
|
||||
MARKETING_VERSION = 3.3.3;
|
||||
MTL_ENABLE_DEBUG_INFO = INCLUDE_SOURCE;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
@@ -1625,7 +1625,7 @@
|
||||
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Distribution";
|
||||
CODE_SIGN_STYLE = Manual;
|
||||
COPY_PHASE_STRIP = NO;
|
||||
CURRENT_PROJECT_VERSION = 2150;
|
||||
CURRENT_PROJECT_VERSION = 2151;
|
||||
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
|
||||
DEVELOPMENT_TEAM = "";
|
||||
"DEVELOPMENT_TEAM[sdk=iphoneos*]" = 53CWBG3QUC;
|
||||
@@ -1707,7 +1707,7 @@
|
||||
"@executable_path/../../Frameworks",
|
||||
);
|
||||
LIBRARY_SEARCH_PATHS = "$(SDKROOT)/usr/lib/swift$(inherited)";
|
||||
MARKETING_VERSION = 3.3.2;
|
||||
MARKETING_VERSION = 3.3.3;
|
||||
MTL_FAST_MATH = YES;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = org.streetwriters.notesnook.share;
|
||||
PRODUCT_NAME = "$(TARGET_NAME)";
|
||||
|
||||
File diff suppressed because one or more lines are too long
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@notesnook/mobile",
|
||||
"version": "3.3.2",
|
||||
"version": "3.3.3",
|
||||
"private": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"workspaces": [
|
||||
|
||||
4
apps/web/package-lock.json
generated
4
apps/web/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@notesnook/web",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"hasInstallScript": true,
|
||||
"license": "GPL-3.0-or-later",
|
||||
"dependencies": {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@notesnook/web",
|
||||
"description": "Your private note taking space",
|
||||
"version": "3.3.0",
|
||||
"version": "3.3.1",
|
||||
"private": true,
|
||||
"main": "./src/app.js",
|
||||
"homepage": "https://notesnook.com/",
|
||||
|
||||
@@ -87,6 +87,8 @@ export async function scheduleFullBackups() {
|
||||
}
|
||||
|
||||
export async function shouldAddAutoBackupsDisabledNotice() {
|
||||
if (isIgnored("autoBackupsOff")) return false;
|
||||
|
||||
const user = await db.user.getUser();
|
||||
if (!user) return false;
|
||||
|
||||
|
||||
@@ -50,7 +50,6 @@ const TRIAL_PERIODS: Record<Period, number> = {
|
||||
};
|
||||
|
||||
export function toPricingInfo(plan: Plan, user: User | undefined): PricingInfo {
|
||||
console.log("TO PRICING INFO", plan);
|
||||
return {
|
||||
country: plan.country,
|
||||
period: plan.period,
|
||||
@@ -58,9 +57,9 @@ export function toPricingInfo(plan: Plan, user: User | undefined): PricingInfo {
|
||||
currency: plan.currency,
|
||||
id: plan.id,
|
||||
period: plan.period,
|
||||
subtotal: formatPrice(plan.price.gross, plan.currency),
|
||||
subtotal: formatPrice(plan.price.net, plan.currency),
|
||||
tax: formatPrice(plan.price.tax, plan.currency),
|
||||
total: formatPrice(plan.price.net, plan.currency),
|
||||
total: formatPrice(plan.price.gross, plan.currency),
|
||||
trial_period: isTrialAvailableForPlan(plan.plan, user)
|
||||
? {
|
||||
frequency: TRIAL_PERIODS[plan.period]
|
||||
@@ -74,9 +73,9 @@ export function toPricingInfo(plan: Plan, user: User | undefined): PricingInfo {
|
||||
currency: plan.currency,
|
||||
id: plan.id,
|
||||
period: plan.period,
|
||||
subtotal: formatPrice(plan.price.gross, plan.currency),
|
||||
subtotal: formatPrice(plan.price.net, plan.currency),
|
||||
tax: formatPrice(plan.price.tax, plan.currency),
|
||||
total: formatPrice(plan.price.net, plan.currency)
|
||||
total: formatPrice(plan.price.gross, plan.currency)
|
||||
}
|
||||
: undefined
|
||||
};
|
||||
|
||||
@@ -245,7 +245,7 @@ function getPricingInfo(
|
||||
id: price.price_id,
|
||||
period: options.period,
|
||||
subtotal: formatPrice(
|
||||
data.recurring_totals.subtotal,
|
||||
data.recurring_totals.subtotal - data.recurring_totals.discount,
|
||||
data.currency_code
|
||||
),
|
||||
total: formatPrice(data.recurring_totals.total, data.currency_code),
|
||||
@@ -256,7 +256,10 @@ function getPricingInfo(
|
||||
currency: data.currency_code,
|
||||
id: price.price_id,
|
||||
period: options.period,
|
||||
subtotal: formatPrice(totals.subtotal, data.currency_code),
|
||||
subtotal: formatPrice(
|
||||
totals.subtotal - totals.discount,
|
||||
data.currency_code
|
||||
),
|
||||
total: formatPrice(totals.total, data.currency_code),
|
||||
tax: formatPrice(totals.tax, data.currency_code),
|
||||
trial_period: price.trial_period
|
||||
|
||||
@@ -22,7 +22,7 @@ import { updateStatus } from "../hooks/use-status";
|
||||
import {
|
||||
Gateway,
|
||||
WEB_EXTENSION_CHANNEL_EVENTS
|
||||
} from "@notesnook/web-clipper/dist/common/bridge";
|
||||
} from "@notesnook/web-clipper/common/bridge.js";
|
||||
import { Extension } from "../components/icons";
|
||||
|
||||
export class WebExtensionRelay {
|
||||
|
||||
@@ -23,7 +23,7 @@ import {
|
||||
NotebookReference,
|
||||
Server,
|
||||
Clip
|
||||
} from "@notesnook/web-clipper/dist/common/bridge";
|
||||
} from "@notesnook/web-clipper/common/bridge.js";
|
||||
import { store as appstore } from "../stores/app-store";
|
||||
import { h } from "./html";
|
||||
import { sanitizeFilename } from "@notesnook/common";
|
||||
|
||||
@@ -119,7 +119,7 @@ function Checkout() {
|
||||
|
||||
useEffect(() => {
|
||||
if (currentStep === 2) {
|
||||
var event = EV.subscribe(EVENTS.userSubscriptionUpdated, () => {
|
||||
const event = EV.subscribe(EVENTS.userSubscriptionUpdated, () => {
|
||||
hardNavigate("/notes#/welcome");
|
||||
});
|
||||
return () => {
|
||||
|
||||
@@ -2,7 +2,31 @@
|
||||
"name": "@notesnook/web-clipper",
|
||||
"version": "0.3.4",
|
||||
"private": true,
|
||||
"main": "./dist/index.js",
|
||||
"main": "./dist/cjs/index.js",
|
||||
"module": "./dist/esm/index.js",
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"exports": {
|
||||
".": {
|
||||
"require": {
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"default": "./dist/cjs/index.js"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/types/index.d.ts",
|
||||
"default": "./dist/esm/index.js"
|
||||
}
|
||||
},
|
||||
"./*": {
|
||||
"require": {
|
||||
"types": "./dist/types/*",
|
||||
"default": "./dist/cjs/*"
|
||||
},
|
||||
"import": {
|
||||
"types": "./dist/types/*",
|
||||
"default": "./dist/esm/*"
|
||||
}
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@emotion/react": "11.11.1",
|
||||
"@mdi/js": "7.4.47",
|
||||
@@ -28,7 +52,7 @@
|
||||
"build:chrome": "cross-env MANIFEST_VERSION=3 node build-utils/build.js",
|
||||
"dev:chrome": "cross-env MANIFEST_VERSION=3 node build-utils/dev.js",
|
||||
"dev:firefox": "cross-env MANIFEST_VERSION=2 node build-utils/dev.js",
|
||||
"build": "tsc"
|
||||
"build": "node ../../scripts/build.mjs"
|
||||
},
|
||||
"browserslist": {
|
||||
"production": [
|
||||
@@ -94,4 +118,4 @@
|
||||
},
|
||||
"homepage": "https://notesnook.com/",
|
||||
"repository": "https://github.com/streetwriters/notesnook"
|
||||
}
|
||||
}
|
||||
|
||||
5
fastlane/metadata/android/en-US/changelogs/15359.txt
Normal file
5
fastlane/metadata/android/en-US/changelogs/15359.txt
Normal file
@@ -0,0 +1,5 @@
|
||||
- We have launches new pricing plans, Essential, Pro and Believer
|
||||
- Free users can now upload attachments and create private vault
|
||||
- Minor bug fixes and improvements
|
||||
|
||||
Thank you for using Notesnook!
|
||||
@@ -1,6 +0,0 @@
|
||||
{
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||
"useNx": true,
|
||||
"version": "independent",
|
||||
"packages": ["packages/*", "apps/*", "extensions/*", "servers/*"]
|
||||
}
|
||||
76
nx.json
76
nx.json
@@ -1,76 +0,0 @@
|
||||
{
|
||||
"targetDefaults": {
|
||||
"build": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": [
|
||||
"{projectRoot}/build",
|
||||
"{projectRoot}/dist",
|
||||
"{projectRoot}/languages",
|
||||
"{projectRoot}/locales",
|
||||
"{projectRoot}/src/extensions/code-block/languages"
|
||||
],
|
||||
"cache": true
|
||||
},
|
||||
"release": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["{projectRoot}/build"]
|
||||
},
|
||||
"build:test": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["{projectRoot}/build"],
|
||||
"cache": true
|
||||
},
|
||||
"build:beta": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["{projectRoot}/build"]
|
||||
},
|
||||
"build:desktop": {
|
||||
"dependsOn": ["^build"],
|
||||
"outputs": ["{projectRoot}/build"],
|
||||
"cache": true
|
||||
},
|
||||
"start": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"start:desktop": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"test:e2e": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"test": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"run-android": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"run-ios": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"build-ios": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"build-android": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"release-android": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"release-android-bundle": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"release-ios": {
|
||||
"dependsOn": ["^build"]
|
||||
},
|
||||
"repack": {
|
||||
"dependsOn": ["^build"]
|
||||
}
|
||||
},
|
||||
"namedInputs": {
|
||||
"default": ["{projectRoot}/**/*", "sharedGlobals"],
|
||||
"sharedGlobals": [],
|
||||
"production": ["default"]
|
||||
},
|
||||
"parallel": 4,
|
||||
"nxCloudAccessToken": "ZWM3ODgxNDgtNGUzZC00MjQ0LWE3MzMtZDdhMzE3ZGY2MWFlfHJlYWQ="
|
||||
}
|
||||
4682
package-lock.json
generated
4682
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
117
package.json
117
package.json
@@ -5,46 +5,49 @@
|
||||
"prepare": "husky install && npm run bootstrap",
|
||||
"bootstrap": "node scripts/bootstrap.mjs",
|
||||
"clean": "node scripts/clean.mjs",
|
||||
"build": "nx run-many --target=build --all --exclude=@notesnook/mobile,@notesnook/web",
|
||||
"build:web": "nx build @notesnook/web",
|
||||
"build:vericrypt": "nx build @notesnook/vericrypt",
|
||||
"build:test:web": "nx build:test @notesnook/web",
|
||||
"build:beta:web": "nx build:beta @notesnook/web",
|
||||
"start:web": "nx start @notesnook/web",
|
||||
"start:theme-builder": "nx start @notesnook/theme-builder",
|
||||
"build:theme-builder": "nx build @notesnook/theme-builder",
|
||||
"start:vericrypt": "nx start @notesnook/vericrypt",
|
||||
"start:desktop": "nx start @notesnook/desktop",
|
||||
"test:web": "nx test @notesnook/web",
|
||||
"test:core": "nx test @notesnook/core",
|
||||
"start:android": "nx run-android @notesnook/mobile",
|
||||
"start:ios": "nx run-ios @notesnook/mobile",
|
||||
"prepare:ios": "nx install-pods @notesnook/mobile",
|
||||
"build:ios": "nx build-ios @notesnook/mobile",
|
||||
"build:android": "nx build-android @notesnook/mobile",
|
||||
"build:android:debug": "nx build-android-debug @notesnook/mobile",
|
||||
"release:android": "nx release-android @notesnook/mobile",
|
||||
"release:android:bundle": "nx release-android-bundle @notesnook/mobile",
|
||||
"test:ios": "nx e2e-ios @notesnook/mobile",
|
||||
"test:android": "nx e2e-android @notesnook/mobile",
|
||||
"test:android:debug": "nx e2e-android-debug @notesnook/mobile",
|
||||
"start:metro": "nx start @notesnook/mobile",
|
||||
"start:repack": "nx repack @notesnook/mobile",
|
||||
"start:editor-mobile": "nx start @notesnook/editor-mobile",
|
||||
"start:editor": "nx start @notesnook/editor",
|
||||
"start:server:themes": "nx start @notesnook/themes-server",
|
||||
"build:intl": "nx build @notesnook/intl",
|
||||
"start:intl": "nx start @notesnook/intl",
|
||||
"build": "npm run tx -- build --all --exclude=mobile,web,monograph,theme-builder,vericrypt",
|
||||
"build:web": "npm run tx web:build",
|
||||
"build:vericrypt": "npm run tx vericrypt:build",
|
||||
"build:test:web": "npm run tx web:build:test",
|
||||
"build:beta:web": "npm run tx web:build:beta",
|
||||
"start:web": "npm run tx web:start",
|
||||
"start:theme-builder": "npm run tx theme-builder:start",
|
||||
"build:theme-builder": "npm run tx theme-builder:build",
|
||||
"start:vericrypt": "npm run tx vericrypt:start",
|
||||
"start:desktop": "npm run tx desktop:start",
|
||||
"test:web": "npm run tx web:test",
|
||||
"test:core": "npm run tx core:test",
|
||||
"start:android": "npm run tx mobile:run-android",
|
||||
"start:ios": "npm run tx mobile:run-ios",
|
||||
"prepare:ios": "npm run tx mobile:install-pods",
|
||||
"build:ios": "npm run tx mobile:build-ios",
|
||||
"build:android": "npm run tx mobile:build-android",
|
||||
"build:android:debug": "npm run tx mobile:build-android-debug",
|
||||
"release:android": "npm run tx mobile:release-android",
|
||||
"release:android:bundle": "npm run tx mobile:release-android-bundle",
|
||||
"test:ios": "npm run tx mobile:e2e-ios",
|
||||
"test:android": "npm run tx mobile:e2e-android",
|
||||
"test:android:debug": "npm run tx mobile:e2e-android-debug",
|
||||
"start:metro": "npm run tx mobile:start",
|
||||
"start:repack": "npm run tx mobile:repack",
|
||||
"start:editor-mobile": "npm run tx editor-mobile:start",
|
||||
"start:editor": "npm run tx editor:start",
|
||||
"start:server:themes": "npm run tx themes-server:start",
|
||||
"build:intl": "npm run tx intl:build",
|
||||
"start:intl": "npm run tx intl:start",
|
||||
"prettier": "npx prettier . --write",
|
||||
"lint": "npx eslint ./apps/ ./packages/",
|
||||
"linc": "npx eslint ./apps/ ./packages/ --cache"
|
||||
"linc": "npx eslint ./apps/ ./packages/ --cache",
|
||||
"tx": "node scripts/execute.mjs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@commitlint/cli": "^17.1.1",
|
||||
"@types/node": "^18.7.13",
|
||||
"@typescript-eslint/eslint-plugin": "^5.59.9",
|
||||
"@typescript-eslint/parser": "^5.59.9",
|
||||
"@typescript/native-preview": "^7.0.0-dev.20251006.1",
|
||||
"cross-env": "^7.0.3",
|
||||
"dotenv": "^17.2.3",
|
||||
"eslint": "^8.42.0",
|
||||
"eslint-config-react-app": "^7.0.1",
|
||||
"eslint-config-react-hooks": "^1.0.0",
|
||||
@@ -58,13 +61,13 @@
|
||||
"husky": "^8.0.1",
|
||||
"prettier": "^2.8.8",
|
||||
"serve": "^14.0.1",
|
||||
"tsdown": "^0.15.6",
|
||||
"tsup": "^8.1.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"eslint-plugin-header": "^3.1.1",
|
||||
"fdir": "^6.0.2",
|
||||
"fdir": "^6.5.0",
|
||||
"listr2": "^8.2.3",
|
||||
"nx": "^21.6.3",
|
||||
"patch-package": "^7.0.0",
|
||||
"rxjs": "^7.8.1",
|
||||
"typescript": "^5.6.3",
|
||||
@@ -72,26 +75,42 @@
|
||||
},
|
||||
"license": "GPL-3.0-or-later",
|
||||
"volta": {
|
||||
"node": "20.12.0"
|
||||
"node": "22.20.0"
|
||||
},
|
||||
"taskRunner": {
|
||||
"projects": [
|
||||
"packages/**",
|
||||
"apps/**",
|
||||
"extensions/**",
|
||||
"servers/**"
|
||||
"packages/*",
|
||||
"apps/*",
|
||||
"extensions/*",
|
||||
"servers/*"
|
||||
],
|
||||
"taskDependencies": {
|
||||
"build": [
|
||||
"build"
|
||||
],
|
||||
"release": [
|
||||
"build"
|
||||
],
|
||||
"build:desktop": [
|
||||
"build"
|
||||
]
|
||||
}
|
||||
"tasks": [
|
||||
{
|
||||
"dependencies": [
|
||||
"build"
|
||||
],
|
||||
"commands": [
|
||||
"start",
|
||||
"build",
|
||||
"release",
|
||||
"build:test",
|
||||
"build:beta",
|
||||
"build:desktop",
|
||||
"start",
|
||||
"start:desktop",
|
||||
"test:e2e",
|
||||
"test",
|
||||
"run-android",
|
||||
"run-ios",
|
||||
"build-ios",
|
||||
"build-android",
|
||||
"release-android",
|
||||
"release-android-bundle",
|
||||
"release-ios",
|
||||
"repack"
|
||||
]
|
||||
}
|
||||
]
|
||||
},
|
||||
"packageManager": "yarn@1.22.22+sha512.a6b2f7906b721bba3d67d4aff083df04dad64c399707841b7acf00f6b133b7ac24255f2652fa22ae3534329dc6180534e98d17432037ff6fd140556e2bb3137e"
|
||||
}
|
||||
|
||||
2755
packages/clipper/package-lock.json
generated
2755
packages/clipper/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -11,9 +11,8 @@
|
||||
"main": "dist/index.js",
|
||||
"devDependencies": {
|
||||
"@playwright/test": "1.48.2",
|
||||
"slugify": "1.6.6",
|
||||
"webpack": "5.88.2",
|
||||
"webpack-cli": "5.1.4"
|
||||
"@rsbuild/core": "^1.5.13",
|
||||
"slugify": "1.6.6"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
@@ -23,7 +22,7 @@
|
||||
"url": "git+https://github.com/streetwriters/notesnook.git"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsc && yarn webpack -c webpack.config.js",
|
||||
"build": "tsc && npx rsbuild build",
|
||||
"prepublishOnly": "npm run build",
|
||||
"test": "playwright test",
|
||||
"postinstall": "patch-package",
|
||||
@@ -38,4 +37,4 @@
|
||||
"hyperapp": "^2.0.22",
|
||||
"specificity": "^0.4.1"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,27 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
const path = require("path");
|
||||
module.exports = {
|
||||
entry: ["./dist/index.global.js"],
|
||||
import { defineConfig } from "@rsbuild/core";
|
||||
import path from "path";
|
||||
|
||||
export default defineConfig({
|
||||
source: {
|
||||
entry: {
|
||||
global: "./dist/index.global.js"
|
||||
}
|
||||
},
|
||||
mode: "production",
|
||||
output: {
|
||||
filename: "clipper.bundle.js",
|
||||
path: path.resolve(
|
||||
__dirname,
|
||||
"../../apps/mobile/native/ios/extension.bundle"
|
||||
)
|
||||
target: "node",
|
||||
cleanDistPath: false,
|
||||
filename: {
|
||||
js: "clipper.bundle.js"
|
||||
},
|
||||
distPath: {
|
||||
root: path.resolve(
|
||||
__dirname,
|
||||
"../../apps/mobile/native/ios/extension.bundle"
|
||||
)
|
||||
}
|
||||
}
|
||||
};
|
||||
});
|
||||
@@ -222,7 +222,7 @@ export const tiptapKeys = {
|
||||
type: "tiptap"
|
||||
},
|
||||
insertParagraph: {
|
||||
keys: "Mod-Shift-0",
|
||||
keys: "Mod-Alt-0",
|
||||
description: "Insert paragraph",
|
||||
category: "Editor",
|
||||
type: "tiptap"
|
||||
|
||||
@@ -68,20 +68,23 @@ test("editing the same note should create multiple history sessions", () =>
|
||||
|
||||
test("restoring an old session should replace note's content", () =>
|
||||
noteTest({ ...TEST_NOTE, sessionId: Date.now() }).then(async ({ db, id }) => {
|
||||
await delay(1000);
|
||||
let editedContent = {
|
||||
data: TEST_NOTE.content.data + "<p>Some new content</p>",
|
||||
type: "tiptap"
|
||||
};
|
||||
|
||||
const sessionId = `${Date.now() + 10000}`;
|
||||
await db.notes.add({
|
||||
id: id,
|
||||
content: editedContent,
|
||||
sessionId: Date.now() + 10000
|
||||
sessionId
|
||||
});
|
||||
|
||||
const [, firstVersion] = await db.noteHistory
|
||||
.get(id)
|
||||
.items(undefined, { sortBy: "dateModified", sortDirection: "desc" });
|
||||
expect(firstVersion.id).not.toBe(`${id}_${sessionId}`);
|
||||
await db.noteHistory.restore(firstVersion.id);
|
||||
|
||||
const contentId = (await db.notes.note(id)).contentId;
|
||||
@@ -138,15 +141,17 @@ test("return empty array if no history available", () =>
|
||||
|
||||
test("auto clear sessions if they exceed the limit", () =>
|
||||
noteTest({ ...TEST_NOTE, sessionId: Date.now() }).then(async ({ db, id }) => {
|
||||
await delay(1000);
|
||||
let editedContent = {
|
||||
data: TEST_NOTE.content.data + "<p>Some new content</p>",
|
||||
type: "tiptap"
|
||||
};
|
||||
|
||||
const sessionId = `${Date.now() + 10000}`;
|
||||
await db.notes.add({
|
||||
id: id,
|
||||
content: editedContent,
|
||||
sessionId: `${Date.now() + 10000}`
|
||||
sessionId
|
||||
});
|
||||
|
||||
expect(await db.noteHistory.get(id).count()).toBe(2);
|
||||
@@ -157,6 +162,7 @@ test("auto clear sessions if they exceed the limit", () =>
|
||||
expect(sessions).toHaveLength(1);
|
||||
|
||||
const content = await db.noteHistory.content(sessions[0].id);
|
||||
expect(sessions[0].id).toBe(`${id}_${sessionId}`);
|
||||
expect(content.data).toBe(editedContent.data);
|
||||
}));
|
||||
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup-node src/index.ts",
|
||||
"build": "tsdown src/index.ts",
|
||||
"prepublishOnly": "npm run build",
|
||||
"watch": "npm run build -- --watch"
|
||||
},
|
||||
|
||||
711
packages/editor/package-lock.json
generated
711
packages/editor/package-lock.json
generated
@@ -66,6 +66,7 @@
|
||||
"devDependencies": {
|
||||
"@emotion/react": "11.11.1",
|
||||
"@mdi/js": "7.4.47",
|
||||
"@rslib/core": "^0.15.0",
|
||||
"@theme-ui/components": "0.16.1",
|
||||
"@theme-ui/core": "0.16.1",
|
||||
"@types/katex": "0.16.7",
|
||||
@@ -77,6 +78,7 @@
|
||||
"happy-dom": "16.0.1",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"nodemon": "^3.1.7",
|
||||
"prismjs": "^1.30.0",
|
||||
"prosemirror-test-builder": "^1.1.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
@@ -260,6 +262,180 @@
|
||||
"react-modal": ">=3"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi/-/napi-0.37.0.tgz",
|
||||
"integrity": "sha512-Hb4o6h1Pf6yRUAX07DR4JVY7dmQw+RVQMW5/m55GoiAT/VRoKCWBtIUPPOnqDVhbx1Cjfil9b6EDrgJsUAujEQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ast-grep/napi-darwin-arm64": "0.37.0",
|
||||
"@ast-grep/napi-darwin-x64": "0.37.0",
|
||||
"@ast-grep/napi-linux-arm64-gnu": "0.37.0",
|
||||
"@ast-grep/napi-linux-arm64-musl": "0.37.0",
|
||||
"@ast-grep/napi-linux-x64-gnu": "0.37.0",
|
||||
"@ast-grep/napi-linux-x64-musl": "0.37.0",
|
||||
"@ast-grep/napi-win32-arm64-msvc": "0.37.0",
|
||||
"@ast-grep/napi-win32-ia32-msvc": "0.37.0",
|
||||
"@ast-grep/napi-win32-x64-msvc": "0.37.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-darwin-arm64": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-arm64/-/napi-darwin-arm64-0.37.0.tgz",
|
||||
"integrity": "sha512-QAiIiaAbLvMEg/yBbyKn+p1gX2/FuaC0SMf7D7capm/oG4xGMzdeaQIcSosF4TCxxV+hIH4Bz9e4/u7w6Bnk3Q==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-darwin-x64": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-darwin-x64/-/napi-darwin-x64-0.37.0.tgz",
|
||||
"integrity": "sha512-zvcvdgekd4ySV3zUbUp8HF5nk5zqwiMXTuVzTUdl/w08O7JjM6XPOIVT+d2o/MqwM9rsXdzdergY5oY2RdhSPA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-linux-arm64-gnu": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-gnu/-/napi-linux-arm64-gnu-0.37.0.tgz",
|
||||
"integrity": "sha512-L7Sj0lXy8X+BqSMgr1LB8cCoWk0rericdeu+dC8/c8zpsav5Oo2IQKY1PmiZ7H8IHoFBbURLf8iklY9wsD+cyA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-linux-arm64-musl": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-arm64-musl/-/napi-linux-arm64-musl-0.37.0.tgz",
|
||||
"integrity": "sha512-LF9sAvYy6es/OdyJDO3RwkX3I82Vkfsng1sqUBcoWC1jVb1wX5YVzHtpQox9JrEhGl+bNp7FYxB4Qba9OdA5GA==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-linux-x64-gnu": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-gnu/-/napi-linux-x64-gnu-0.37.0.tgz",
|
||||
"integrity": "sha512-TViz5/klqre6aSmJzswEIjApnGjJzstG/SE8VDWsrftMBMYt2PTu3MeluZVwzSqDao8doT/P+6U11dU05UOgxw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-linux-x64-musl": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-linux-x64-musl/-/napi-linux-x64-musl-0.37.0.tgz",
|
||||
"integrity": "sha512-/BcCH33S9E3ovOAEoxYngUNXgb+JLg991sdyiNP2bSoYd30a9RHrG7CYwW6fMgua3ijQ474eV6cq9yZO1bCpXg==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-win32-arm64-msvc": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-arm64-msvc/-/napi-win32-arm64-msvc-0.37.0.tgz",
|
||||
"integrity": "sha512-TjQA4cFoIEW2bgjLkaL9yqT4XWuuLa5MCNd0VCDhGRDMNQ9+rhwi9eLOWRaap3xzT7g+nlbcEHL3AkVCD2+b3A==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-win32-ia32-msvc": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-ia32-msvc/-/napi-win32-ia32-msvc-0.37.0.tgz",
|
||||
"integrity": "sha512-uNmVka8fJCdYsyOlF9aZqQMLTatEYBynjChVTzUfFMDfmZ0bihs/YTqJVbkSm8TZM7CUX82apvn50z/dX5iWRA==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@ast-grep/napi-win32-x64-msvc": {
|
||||
"version": "0.37.0",
|
||||
"resolved": "https://registry.npmjs.org/@ast-grep/napi-win32-x64-msvc/-/napi-win32-x64-msvc-0.37.0.tgz",
|
||||
"integrity": "sha512-vCiFOT3hSCQuHHfZ933GAwnPzmL0G04JxQEsBRfqONywyT8bSdDc/ECpAfr3S9VcS4JZ9/F6tkePKW/Om2Dq2g==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
],
|
||||
"engines": {
|
||||
"node": ">= 10"
|
||||
}
|
||||
},
|
||||
"node_modules/@azure/msal-browser": {
|
||||
"version": "3.28.1",
|
||||
"resolved": "https://registry.npmjs.org/@azure/msal-browser/-/msal-browser-3.28.1.tgz",
|
||||
@@ -489,6 +665,40 @@
|
||||
"node": ">=6.9.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/core": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/core/-/core-1.5.0.tgz",
|
||||
"integrity": "sha512-sbP8GzB1WDzacS8fgNPpHlp6C9VZe+SJP3F90W9rLemaQj2PzIuTEl1qDOYQf58YIpyjViI24y9aPWCjEzY2cg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/wasi-threads": "1.1.0",
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/runtime": {
|
||||
"version": "1.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/runtime/-/runtime-1.5.0.tgz",
|
||||
"integrity": "sha512-97/BJ3iXHww3djw6hYIfErCZFee7qCtrneuLa20UXFCOTCfBM2cvQHjWJ2EG0s0MtdNwInarqCTz35i4wWXHsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emnapi/wasi-threads": {
|
||||
"version": "1.1.0",
|
||||
"resolved": "https://registry.npmjs.org/@emnapi/wasi-threads/-/wasi-threads-1.1.0.tgz",
|
||||
"integrity": "sha512-WI0DdZ8xFSbgMjR1sFsKABJ/C5OnRrjT06JXbZKexJGrDuPTzZdDYfFlsgcCXCyf+suG5QU2e/y1Wo2V/OapLQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@emotion/babel-plugin": {
|
||||
"version": "11.12.0",
|
||||
"resolved": "https://registry.npmjs.org/@emotion/babel-plugin/-/babel-plugin-11.12.0.tgz",
|
||||
@@ -1074,6 +1284,78 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@module-federation/error-codes": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/error-codes/-/error-codes-0.18.0.tgz",
|
||||
"integrity": "sha512-Woonm8ehyVIUPXChmbu80Zj6uJkC0dD9SJUZ/wOPtO8iiz/m+dkrOugAuKgoiR6qH4F+yorWila954tBz4uKsQ==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@module-federation/runtime": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/runtime/-/runtime-0.18.0.tgz",
|
||||
"integrity": "sha512-+C4YtoSztM7nHwNyZl6dQKGUVJdsPrUdaf3HIKReg/GQbrt9uvOlUWo2NXMZ8vDAnf/QRrpSYAwXHmWDn9Obaw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@module-federation/error-codes": "0.18.0",
|
||||
"@module-federation/runtime-core": "0.18.0",
|
||||
"@module-federation/sdk": "0.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@module-federation/runtime-core": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/runtime-core/-/runtime-core-0.18.0.tgz",
|
||||
"integrity": "sha512-ZyYhrDyVAhUzriOsVfgL6vwd+5ebYm595Y13KeMf6TKDRoUHBMTLGQ8WM4TDj8JNsy7LigncK8C03fn97of0QQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@module-federation/error-codes": "0.18.0",
|
||||
"@module-federation/sdk": "0.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@module-federation/runtime-tools": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/runtime-tools/-/runtime-tools-0.18.0.tgz",
|
||||
"integrity": "sha512-fSga9o4t1UfXNV/Kh6qFvRyZpPp3EHSPRISNeyT8ZoTpzDNiYzhtw0BPUSSD8m6C6XQh2s/11rI4g80UY+d+hA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@module-federation/runtime": "0.18.0",
|
||||
"@module-federation/webpack-bundler-runtime": "0.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@module-federation/sdk": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/sdk/-/sdk-0.18.0.tgz",
|
||||
"integrity": "sha512-Lo/Feq73tO2unjmpRfyyoUkTVoejhItXOk/h5C+4cistnHbTV8XHrW/13fD5e1Iu60heVdAhhelJd6F898Ve9A==",
|
||||
"dev": true,
|
||||
"license": "MIT"
|
||||
},
|
||||
"node_modules/@module-federation/webpack-bundler-runtime": {
|
||||
"version": "0.18.0",
|
||||
"resolved": "https://registry.npmjs.org/@module-federation/webpack-bundler-runtime/-/webpack-bundler-runtime-0.18.0.tgz",
|
||||
"integrity": "sha512-TEvErbF+YQ+6IFimhUYKK3a5wapD90d90sLsNpcu2kB3QGT7t4nIluE25duXuZDVUKLz86tEPrza/oaaCWTpvQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@module-federation/runtime": "0.18.0",
|
||||
"@module-federation/sdk": "0.18.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@napi-rs/wasm-runtime": {
|
||||
"version": "1.0.6",
|
||||
"resolved": "https://registry.npmjs.org/@napi-rs/wasm-runtime/-/wasm-runtime-1.0.6.tgz",
|
||||
"integrity": "sha512-DXj75ewm11LIWUk198QSKUTxjyRjsBwk09MuMk5DGK+GDUtyPhhEHOGP/Xwwj3DjQXXkivoBirmOnKrLfc0+9g==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@emnapi/core": "^1.5.0",
|
||||
"@emnapi/runtime": "^1.5.0",
|
||||
"@tybys/wasm-util": "^0.10.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@notesnook-importer/core": {
|
||||
"version": "2.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@notesnook-importer/core/-/core-2.2.2.tgz",
|
||||
@@ -1445,6 +1727,247 @@
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rsbuild/core": {
|
||||
"version": "1.5.13",
|
||||
"resolved": "https://registry.npmjs.org/@rsbuild/core/-/core-1.5.13.tgz",
|
||||
"integrity": "sha512-P+TCvZCVpBYZ3GDdnzR/tZKicE41khJIqIRlJYnEc9dwUfX1/eqRf8lA8yrsbB5iZbSfj1iOoH1N25cCQ3hhuA==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rspack/core": "1.5.8",
|
||||
"@rspack/lite-tapable": "~1.0.1",
|
||||
"@swc/helpers": "^0.5.17",
|
||||
"core-js": "~3.45.1",
|
||||
"jiti": "^2.6.0"
|
||||
},
|
||||
"bin": {
|
||||
"rsbuild": "bin/rsbuild.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.12.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@rslib/core": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/@rslib/core/-/core-0.15.0.tgz",
|
||||
"integrity": "sha512-ZxDwEU38qsM32VpW4Dy7oNf6MxgrRAgYxVsuv8v+aKm4pIOSs0nzDTJHsa2vhKjFdyRtgnHObZ6pjoJ0cmcU3A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@rsbuild/core": "~1.5.13",
|
||||
"rsbuild-plugin-dts": "0.15.0"
|
||||
},
|
||||
"bin": {
|
||||
"rslib": "bin/rslib.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@microsoft/api-extractor": "^7",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@microsoft/api-extractor": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding/-/binding-1.5.8.tgz",
|
||||
"integrity": "sha512-/91CzhRl9r5BIQCgGsS7jA6MDbw1I2BQpbfcUUdkdKl2P79K3Zo/Mw/TvKzS86catwLaUQEgkGRmYawOfPg7ow==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optionalDependencies": {
|
||||
"@rspack/binding-darwin-arm64": "1.5.8",
|
||||
"@rspack/binding-darwin-x64": "1.5.8",
|
||||
"@rspack/binding-linux-arm64-gnu": "1.5.8",
|
||||
"@rspack/binding-linux-arm64-musl": "1.5.8",
|
||||
"@rspack/binding-linux-x64-gnu": "1.5.8",
|
||||
"@rspack/binding-linux-x64-musl": "1.5.8",
|
||||
"@rspack/binding-wasm32-wasi": "1.5.8",
|
||||
"@rspack/binding-win32-arm64-msvc": "1.5.8",
|
||||
"@rspack/binding-win32-ia32-msvc": "1.5.8",
|
||||
"@rspack/binding-win32-x64-msvc": "1.5.8"
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding-darwin-arm64": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-arm64/-/binding-darwin-arm64-1.5.8.tgz",
|
||||
"integrity": "sha512-spJfpOSN3f7V90ic45/ET2NKB2ujAViCNmqb0iGurMNQtFRq+7Kd+jvVKKGXKBHBbsQrFhidSWbbqy2PBPGK8g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-darwin-x64": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-darwin-x64/-/binding-darwin-x64-1.5.8.tgz",
|
||||
"integrity": "sha512-YFOzeL1IBknBcri8vjUp43dfUBylCeQnD+9O9p0wZmLAw7DtpN5JEOe2AkGo8kdTqJjYKI+cczJPKIw6lu1LWw==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"darwin"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-arm64-gnu": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-gnu/-/binding-linux-arm64-gnu-1.5.8.tgz",
|
||||
"integrity": "sha512-UAWCsOnpkvy8eAVRo0uipbHXDhnoDq5zmqWTMhpga0/a3yzCp2e+fnjZb/qnFNYb5MeL0O1mwMOYgn1M3oHILQ==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-arm64-musl": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-arm64-musl/-/binding-linux-arm64-musl-1.5.8.tgz",
|
||||
"integrity": "sha512-GnSvGT4GjokPSD45cTtE+g7LgghuxSP1MRmvd+Vp/I8pnxTVSTsebRod4TAqyiv+l11nuS8yqNveK9qiOkBLWw==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-x64-gnu": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-gnu/-/binding-linux-x64-gnu-1.5.8.tgz",
|
||||
"integrity": "sha512-XLxh5n/pzUfxsugz/8rVBv+Tx2nqEM+9rharK69kfooDsQNKyz7PANllBQ/v4svJ+W0BRHnDL4qXSGdteZeEjA==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-linux-x64-musl": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-linux-x64-musl/-/binding-linux-x64-musl-1.5.8.tgz",
|
||||
"integrity": "sha512-gE0+MZmwF+01p9/svpEESkzkLpBkVUG2o03YMpwXYC/maeRRhWvF8BJ7R3i/Ls/jFGSE87dKX5NbRLVzqksq/w==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"linux"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-wasm32-wasi": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-wasm32-wasi/-/binding-wasm32-wasi-1.5.8.tgz",
|
||||
"integrity": "sha512-cfg3niNHeJuxuml1Vy9VvaJrI/5TakzoaZvKX2g5S24wfzR50Eyy4JAsZ+L2voWQQp1yMJbmPYPmnTCTxdJQBQ==",
|
||||
"cpu": [
|
||||
"wasm32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@napi-rs/wasm-runtime": "^1.0.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-arm64-msvc": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-arm64-msvc/-/binding-win32-arm64-msvc-1.5.8.tgz",
|
||||
"integrity": "sha512-7i3ZTHFXKfU/9Jm9XhpMkrdkxO7lfeYMNVEGkuU5dyBfRMQj69dRgPL7zJwc2plXiqu9LUOl+TwDNTjap7Q36g==",
|
||||
"cpu": [
|
||||
"arm64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-ia32-msvc": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-ia32-msvc/-/binding-win32-ia32-msvc-1.5.8.tgz",
|
||||
"integrity": "sha512-7ZPPWO11J+soea1+mnfaPpQt7GIodBM7A86dx6PbXgVEoZmetcWPrCF2NBfXxQWOKJ9L3RYltC4z+ZyXRgMOrw==",
|
||||
"cpu": [
|
||||
"ia32"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/binding-win32-x64-msvc": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/binding-win32-x64-msvc/-/binding-win32-x64-msvc-1.5.8.tgz",
|
||||
"integrity": "sha512-N/zXQgzIxME3YUzXT8qnyzxjqcnXudWOeDh8CAG9zqTCnCiy16SFfQ/cQgEoLlD9geQntV6jx2GbDDI5kpDGMQ==",
|
||||
"cpu": [
|
||||
"x64"
|
||||
],
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"os": [
|
||||
"win32"
|
||||
]
|
||||
},
|
||||
"node_modules/@rspack/core": {
|
||||
"version": "1.5.8",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/core/-/core-1.5.8.tgz",
|
||||
"integrity": "sha512-sUd2LfiDhqYVfvknuoz0+/c+wSpn693xotnG5g1CSWKZArbtwiYzBIVnNlcHGmuoBRsnj/TkSq8dTQ7gwfBroQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@module-federation/runtime-tools": "0.18.0",
|
||||
"@rspack/binding": "1.5.8",
|
||||
"@rspack/lite-tapable": "1.0.1"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@swc/helpers": ">=0.5.1"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@swc/helpers": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/@rspack/lite-tapable": {
|
||||
"version": "1.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@rspack/lite-tapable/-/lite-tapable-1.0.1.tgz",
|
||||
"integrity": "sha512-VynGOEsVw2s8TAlLf/uESfrgfrq2+rcXB1muPJYBWbsm1Oa6r5qVQhjA5ggM6z/coYPrsVMgovl3Ff7Q7OCp1w==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=16.0.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@social-embed/lib": {
|
||||
"version": "0.1.0-next.7",
|
||||
"resolved": "https://registry.npmjs.org/@social-embed/lib/-/lib-0.1.0-next.7.tgz",
|
||||
@@ -1755,6 +2278,49 @@
|
||||
"@styled-system/css": "^5.1.5"
|
||||
}
|
||||
},
|
||||
"node_modules/@swc/helpers": {
|
||||
"version": "0.5.17",
|
||||
"resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.5.17.tgz",
|
||||
"integrity": "sha512-5IKx/Y13RsYd+sauPb2x+U/xZikHjolzfuDgTAl/Tdf3Q8rslRvC19NKDLgAJQ6wsqADk10ntlv08nPFw/gO/A==",
|
||||
"dev": true,
|
||||
"license": "Apache-2.0",
|
||||
"dependencies": {
|
||||
"tslib": "^2.8.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/color-modes": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/color-modes/-/color-modes-0.16.2.tgz",
|
||||
"integrity": "sha512-jWEWx53lxNgWCT38i/kwLV2rsvJz8lVZgi5oImnVwYba9VejXD23q1ckbNFJHosQ8KKXY87ht0KPC6BQFIiHtQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@theme-ui/core": "^0.16.2",
|
||||
"@theme-ui/css": "^0.16.2",
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/color-modes/node_modules/@theme-ui/core": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/core/-/core-0.16.2.tgz",
|
||||
"integrity": "sha512-bBd/ltbwO9vIUjF1jtlOX6XN0IIOdf1vzBp2JCKsSOqdfn84m+XL8OogIe/zOhQ+aM94Nrq4+32tFJc8sFav4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@theme-ui/css": "^0.16.2",
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/components": {
|
||||
"version": "0.16.1",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/components/-/components-0.16.1.tgz",
|
||||
@@ -1800,6 +2366,39 @@
|
||||
"@emotion/react": "^11.11.1"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/theme-provider": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/theme-provider/-/theme-provider-0.16.2.tgz",
|
||||
"integrity": "sha512-LRnVevODcGqO0JyLJ3wht+PV3ZoZcJ7XXLJAJWDoGeII4vZcPQKwVy4Lpz/juHsZppQxKcB3U+sQDGBnP25irQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@theme-ui/color-modes": "^0.16.2",
|
||||
"@theme-ui/core": "^0.16.2",
|
||||
"@theme-ui/css": "^0.16.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@theme-ui/theme-provider/node_modules/@theme-ui/core": {
|
||||
"version": "0.16.2",
|
||||
"resolved": "https://registry.npmjs.org/@theme-ui/core/-/core-0.16.2.tgz",
|
||||
"integrity": "sha512-bBd/ltbwO9vIUjF1jtlOX6XN0IIOdf1vzBp2JCKsSOqdfn84m+XL8OogIe/zOhQ+aM94Nrq4+32tFJc8sFav4Q==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"@theme-ui/css": "^0.16.2",
|
||||
"deepmerge": "^4.2.2"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@emotion/react": "^11.11.1",
|
||||
"react": ">=18"
|
||||
}
|
||||
},
|
||||
"node_modules/@tiptap/core": {
|
||||
"version": "2.6.6",
|
||||
"resolved": "https://registry.npmjs.org/@tiptap/core/-/core-2.6.6.tgz",
|
||||
@@ -2291,6 +2890,17 @@
|
||||
"@tiptap/core": "^2.6.6"
|
||||
}
|
||||
},
|
||||
"node_modules/@tybys/wasm-util": {
|
||||
"version": "0.10.1",
|
||||
"resolved": "https://registry.npmjs.org/@tybys/wasm-util/-/wasm-util-0.10.1.tgz",
|
||||
"integrity": "sha512-9tTaPJLSiejZKx+Bmog4uSubteqTvFrVrURwkmHixBo0G4seD0zUxp98E1DzUBJxLQ3NPwXrGKDiVjwx/DpPsg==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.4.0"
|
||||
}
|
||||
},
|
||||
"node_modules/@types/debug": {
|
||||
"version": "4.1.12",
|
||||
"resolved": "https://registry.npmjs.org/@types/debug/-/debug-4.1.12.tgz",
|
||||
@@ -2922,6 +3532,18 @@
|
||||
"integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==",
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/core-js": {
|
||||
"version": "3.45.1",
|
||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.45.1.tgz",
|
||||
"integrity": "sha512-L4NPsJlCfZsPeXukyzHFlg/i7IIVwHSItR0wg0FLNqYClJ4MQYTYLbC7EkjKYRLZF2iof2MUgN0EGy7MdQFChg==",
|
||||
"dev": true,
|
||||
"hasInstallScript": true,
|
||||
"license": "MIT",
|
||||
"funding": {
|
||||
"type": "opencollective",
|
||||
"url": "https://opencollective.com/core-js"
|
||||
}
|
||||
},
|
||||
"node_modules/cosmiconfig": {
|
||||
"version": "7.1.0",
|
||||
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-7.1.0.tgz",
|
||||
@@ -3154,6 +3776,17 @@
|
||||
"safe-buffer": "^5.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/encoding": {
|
||||
"version": "0.1.13",
|
||||
"resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz",
|
||||
"integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"iconv-lite": "^0.6.2"
|
||||
}
|
||||
},
|
||||
"node_modules/end-of-stream": {
|
||||
"version": "1.4.4",
|
||||
"resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
|
||||
@@ -3638,6 +4271,20 @@
|
||||
"url": "https://github.com/fb55/entities?sponsor=1"
|
||||
}
|
||||
},
|
||||
"node_modules/iconv-lite": {
|
||||
"version": "0.6.3",
|
||||
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
|
||||
"integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"safer-buffer": ">= 2.1.2 < 3.0.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/ieee754": {
|
||||
"version": "1.2.1",
|
||||
"resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
|
||||
@@ -3865,11 +4512,20 @@
|
||||
"whatwg-fetch": "^3.4.1"
|
||||
}
|
||||
},
|
||||
"node_modules/jiti": {
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/jiti/-/jiti-2.6.1.tgz",
|
||||
"integrity": "sha512-ekilCSN1jwRvIbgeg/57YFh8qQDNbwDb9xT/qu2DAHbFFZUicIl4ygVaAvzveMhMVr3LnpSKTNnwt8PoOfmKhQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"bin": {
|
||||
"jiti": "lib/jiti-cli.mjs"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"dev": true
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ=="
|
||||
},
|
||||
"node_modules/js-yaml": {
|
||||
"version": "3.14.1",
|
||||
@@ -4085,7 +4741,6 @@
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
@@ -5437,6 +6092,16 @@
|
||||
"resolved": "https://registry.npmjs.org/prism-themes/-/prism-themes-1.9.0.tgz",
|
||||
"integrity": "sha512-tX2AYsehKDw1EORwBps+WhBFKc2kxfoFpQAjxBndbZKr4fRmMkv47XN0BghC/K1qwodB1otbe4oF23vUTFDokw=="
|
||||
},
|
||||
"node_modules/prismjs": {
|
||||
"version": "1.30.0",
|
||||
"resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.30.0.tgz",
|
||||
"integrity": "sha512-DEvV2ZF2r2/63V+tK8hQvrR2ZGn10srHbXviTlcv7Kpzw8jWiNTqbVgjO3IY8RxrrOUF8VPMQQFysYYYv0YZxw==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=6"
|
||||
}
|
||||
},
|
||||
"node_modules/prop-types": {
|
||||
"version": "15.8.1",
|
||||
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
|
||||
@@ -5708,7 +6373,6 @@
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
@@ -5729,7 +6393,6 @@
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-18.3.1.tgz",
|
||||
"integrity": "sha512-5m4nQKp+rZRb09LNH59GM4BxTh9251/ylbKIbpe7TpGxfJ+9kv6BLkLBXIjjspbgbnIBNqlI23tRnTWT0snUIw==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0",
|
||||
"scheduler": "^0.23.2"
|
||||
@@ -6042,6 +6705,36 @@
|
||||
"resolved": "https://registry.npmjs.org/rope-sequence/-/rope-sequence-1.3.4.tgz",
|
||||
"integrity": "sha512-UT5EDe2cu2E/6O4igUr5PSFs23nvvukicWHx6GnOPlHAiiYbzNuCRQCuiUdHJQcqKalLKlrYJnjY0ySGsXNQXQ=="
|
||||
},
|
||||
"node_modules/rsbuild-plugin-dts": {
|
||||
"version": "0.15.0",
|
||||
"resolved": "https://registry.npmjs.org/rsbuild-plugin-dts/-/rsbuild-plugin-dts-0.15.0.tgz",
|
||||
"integrity": "sha512-qKGCtv4fxKxWZb3DxHpgmP6uY+JAckovBE/92APerORvrtEtqwY6sAEY2UOaRo2ErENOiWhf5yFLE5EhdUsj9A==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ast-grep/napi": "0.37.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=18.12.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@microsoft/api-extractor": "^7",
|
||||
"@rsbuild/core": "1.x",
|
||||
"@typescript/native-preview": "7.x",
|
||||
"typescript": "^5"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"@microsoft/api-extractor": {
|
||||
"optional": true
|
||||
},
|
||||
"@typescript/native-preview": {
|
||||
"optional": true
|
||||
},
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"node_modules/sade": {
|
||||
"version": "1.8.1",
|
||||
"resolved": "https://registry.npmjs.org/sade/-/sade-1.8.1.tgz",
|
||||
@@ -6083,7 +6776,6 @@
|
||||
"version": "0.23.2",
|
||||
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
||||
"integrity": "sha512-UOShsPwz7NrMUqhR6t0hWjFduvOzbtv7toDH1/hIrfRNIDBnnBWd0CwJTGvTpngVlmwGCdP9/Zl/tVrDqcuYzQ==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
}
|
||||
@@ -6480,9 +7172,10 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.2",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
|
||||
"integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
|
||||
"version": "2.8.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
|
||||
"integrity": "sha512-oJFu94HQb+KVduSUQL7wnpmqnfmLsOA/nAh6b6EH0wCEoK0/mPeXU6c3wKDV83MkOuHPRHtSXKKU99IBazS/2w==",
|
||||
"license": "0BSD"
|
||||
},
|
||||
"node_modules/tunnel-agent": {
|
||||
"version": "0.6.0",
|
||||
|
||||
@@ -97,6 +97,7 @@
|
||||
"happy-dom": "16.0.1",
|
||||
"isomorphic-fetch": "^3.0.0",
|
||||
"nodemon": "^3.1.7",
|
||||
"prismjs": "^1.30.0",
|
||||
"prosemirror-test-builder": "^1.1.1",
|
||||
"react": "18.3.1",
|
||||
"react-dom": "18.3.1",
|
||||
|
||||
@@ -23,15 +23,16 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import fs from "fs";
|
||||
import { readFile } from "fs/promises";
|
||||
import path from "path";
|
||||
|
||||
export async function langen(rootDirectory) {
|
||||
const response = await fetch(
|
||||
"https://github.com/PrismJS/prism/raw/master/components.json"
|
||||
const json = JSON.parse(
|
||||
await readFile(
|
||||
path.join(rootDirectory, "node_modules", "prismjs", "components.json"),
|
||||
"utf-8"
|
||||
)
|
||||
);
|
||||
if (!response.ok) return {};
|
||||
|
||||
const json = await response.json();
|
||||
let languages = [];
|
||||
for (const key in json.languages) {
|
||||
if (key === "meta") continue;
|
||||
|
||||
@@ -17,8 +17,14 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
import { keybindings } from "@notesnook/common";
|
||||
import { KeyboardShortcutCommand, mergeAttributes, Node } from "@tiptap/core";
|
||||
import {
|
||||
findParentNodeClosestToPos,
|
||||
KeyboardShortcutCommand,
|
||||
mergeAttributes,
|
||||
Node
|
||||
} from "@tiptap/core";
|
||||
import { Node as ProseMirrorNode } from "@tiptap/pm/model";
|
||||
import { CheckList } from "../check-list/check-list";
|
||||
|
||||
export interface CheckListItemOptions {
|
||||
onReadOnlyChecked?: (node: ProseMirrorNode, checked: boolean) => boolean;
|
||||
@@ -97,94 +103,76 @@ export const CheckListItem = Node.create<CheckListItemOptions>({
|
||||
|
||||
addNodeView() {
|
||||
return ({ node, getPos, editor }) => {
|
||||
const listItem = document.createElement("li");
|
||||
const checkboxWrapper = document.createElement("label");
|
||||
const checkboxStyler = document.createElement("span");
|
||||
const checkbox = document.createElement("input");
|
||||
const content = document.createElement("div");
|
||||
const li = document.createElement("li");
|
||||
if (node.attrs.checked) li.classList.add("checked");
|
||||
else li.classList.remove("checked");
|
||||
|
||||
checkboxWrapper.contentEditable = "false";
|
||||
checkbox.type = "checkbox";
|
||||
function onClick(e: MouseEvent | TouchEvent) {
|
||||
if (e instanceof MouseEvent && e.button !== 0) return;
|
||||
if (!(e.target instanceof HTMLElement)) return;
|
||||
|
||||
checkbox.addEventListener("mousedown", (event) => {
|
||||
if (globalThis.keyboardShown) {
|
||||
event.preventDefault();
|
||||
}
|
||||
});
|
||||
const pos = typeof getPos === "function" ? getPos() : 0;
|
||||
if (typeof pos !== "number") return;
|
||||
const resolvedPos = editor.state.doc.resolve(pos);
|
||||
|
||||
checkbox.addEventListener("change", (event) => {
|
||||
event.preventDefault();
|
||||
// if the editor isn’t editable and we don't have a handler for
|
||||
// readonly checks we have to undo the latest change
|
||||
if (!editor.isEditable && !this.options.onReadOnlyChecked) {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
const { x, y, right } = li.getBoundingClientRect();
|
||||
|
||||
return;
|
||||
const clientX =
|
||||
e instanceof MouseEvent ? e.clientX : e.touches[0].clientX;
|
||||
|
||||
const clientY =
|
||||
e instanceof MouseEvent ? e.clientY : e.touches[0].clientY;
|
||||
|
||||
const hitArea = { width: 40, height: 40 };
|
||||
|
||||
const isRtl =
|
||||
e.target.dir === "rtl" ||
|
||||
findParentNodeClosestToPos(
|
||||
resolvedPos,
|
||||
(node) => !!node.attrs.textDirection
|
||||
)?.node.attrs.textDirection === "rtl";
|
||||
|
||||
let xStart = clientX >= x - hitArea.width;
|
||||
let xEnd = clientX <= x;
|
||||
const yStart = clientY >= y;
|
||||
const yEnd = clientY <= y + hitArea.height;
|
||||
|
||||
if (isRtl) {
|
||||
xEnd = clientX <= right + hitArea.width;
|
||||
xStart = clientX >= right;
|
||||
}
|
||||
|
||||
const { checked } = event.target as any;
|
||||
|
||||
if (editor.isEditable && typeof getPos === "function") {
|
||||
editor
|
||||
.chain()
|
||||
.command(({ tr }) => {
|
||||
const position = getPos();
|
||||
const currentNode = tr.doc.nodeAt(position);
|
||||
|
||||
tr.setNodeMarkup(position, undefined, {
|
||||
...currentNode?.attrs,
|
||||
checked
|
||||
});
|
||||
|
||||
return true;
|
||||
})
|
||||
.run();
|
||||
if (xStart && xEnd && yStart && yEnd) {
|
||||
e.preventDefault();
|
||||
editor.commands.command(({ tr }) => {
|
||||
tr.setNodeAttribute(
|
||||
pos,
|
||||
"checked",
|
||||
!li.classList.contains("checked")
|
||||
);
|
||||
return true;
|
||||
});
|
||||
}
|
||||
if (!editor.isEditable && this.options.onReadOnlyChecked) {
|
||||
// Reset state if onReadOnlyChecked returns false
|
||||
if (!this.options.onReadOnlyChecked(node, checked)) {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
if (node.attrs.checked) {
|
||||
checkbox.setAttribute("checked", "checked");
|
||||
}
|
||||
|
||||
checkboxWrapper.append(checkbox, checkboxStyler);
|
||||
listItem.append(checkboxWrapper, content);
|
||||
li.onmousedown = onClick;
|
||||
li.ontouchstart = onClick;
|
||||
|
||||
return {
|
||||
dom: listItem,
|
||||
contentDOM: content,
|
||||
dom: li,
|
||||
contentDOM: li,
|
||||
update: (updatedNode) => {
|
||||
if (updatedNode.type !== this.type) {
|
||||
return false;
|
||||
}
|
||||
const isNested = updatedNode.lastChild?.type.name === CheckList.name;
|
||||
|
||||
listItem.dataset.checked = updatedNode.attrs.checked;
|
||||
if (updatedNode.attrs.checked) {
|
||||
checkbox.setAttribute("checked", "checked");
|
||||
} else {
|
||||
checkbox.removeAttribute("checked");
|
||||
}
|
||||
if (updatedNode.attrs.checked) li.classList.add("checked");
|
||||
else li.classList.remove("checked");
|
||||
|
||||
return true;
|
||||
}
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
// addInputRules() {
|
||||
// return [
|
||||
// wrappingInputRule({
|
||||
// find: inputRegex,
|
||||
// type: this.type,
|
||||
// getAttributes: (match) => ({
|
||||
// checked: match[match.length - 1] === "x"
|
||||
// })
|
||||
// })
|
||||
// ];
|
||||
// }
|
||||
});
|
||||
|
||||
@@ -42,7 +42,7 @@ export class ClipboardDOMParser extends ProsemirrorDOMParser {
|
||||
convertGoogleDocsChecklist(dom);
|
||||
formatCodeblocks(dom);
|
||||
convertBrToSingleSpacedParagraphs(dom);
|
||||
removeImages(dom);
|
||||
removePremiumFeatures(dom);
|
||||
removeBlockId(dom);
|
||||
}
|
||||
return super.parseSlice(dom, options);
|
||||
@@ -53,7 +53,7 @@ export class ClipboardDOMParser extends ProsemirrorDOMParser {
|
||||
convertGoogleDocsChecklist(dom);
|
||||
formatCodeblocks(dom);
|
||||
convertBrToSingleSpacedParagraphs(dom);
|
||||
removeImages(dom);
|
||||
removePremiumFeatures(dom);
|
||||
removeBlockId(dom);
|
||||
}
|
||||
return super.parse(dom, options);
|
||||
@@ -154,11 +154,29 @@ export function convertGoogleDocsChecklist(dom: HTMLElement | Document) {
|
||||
}
|
||||
}
|
||||
|
||||
export function removeImages(dom: HTMLElement | Document) {
|
||||
let canInsertImages: boolean | null = null;
|
||||
for (const img of dom.querySelectorAll(`img`)) {
|
||||
canInsertImages = canInsertImages ?? hasPermission("insertImage");
|
||||
if (!canInsertImages) img.remove();
|
||||
const premiumFeatures = [
|
||||
{
|
||||
selector: "div.callout",
|
||||
permission: "setCallout"
|
||||
},
|
||||
{
|
||||
selector: 'ul[data-type="outlineList"]',
|
||||
permission: "toggleOutlineList"
|
||||
},
|
||||
{
|
||||
selector: "ul.checklist",
|
||||
permission: "toggleTaskList"
|
||||
}
|
||||
] as const;
|
||||
|
||||
function removePremiumFeatures(dom: HTMLElement | Document) {
|
||||
for (const feature of premiumFeatures) {
|
||||
const elements = dom.querySelectorAll(feature.selector);
|
||||
if (elements.length === 0) continue;
|
||||
|
||||
if (!hasPermission(feature.permission)) {
|
||||
elements.forEach((element) => element.remove());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,171 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`migration > inline image in outline list 1`] = `
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "item 1",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "hello",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"align": undefined,
|
||||
"aspectRatio": 1,
|
||||
"filename": undefined,
|
||||
"hash": undefined,
|
||||
"height": null,
|
||||
"mime": undefined,
|
||||
"progress": 0,
|
||||
"size": undefined,
|
||||
"src": "image.png",
|
||||
"type": "image",
|
||||
"width": null,
|
||||
},
|
||||
"type": "image",
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "world",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "sub item 2",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "sub item 3",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
],
|
||||
"type": "outlineList",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "item 4",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
],
|
||||
"type": "outlineList",
|
||||
},
|
||||
],
|
||||
"type": "doc",
|
||||
}
|
||||
`;
|
||||
|
||||
exports[`migration > inline image in paragraph 1`] = `
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "hello",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"align": undefined,
|
||||
"aspectRatio": 1,
|
||||
"filename": undefined,
|
||||
"hash": undefined,
|
||||
"height": null,
|
||||
"mime": undefined,
|
||||
"progress": 0,
|
||||
"size": undefined,
|
||||
"src": "image.png",
|
||||
"type": "image",
|
||||
"width": null,
|
||||
},
|
||||
"type": "image",
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "world",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "doc",
|
||||
}
|
||||
`;
|
||||
75
packages/editor/src/extensions/image/__tests__/image.test.ts
Normal file
75
packages/editor/src/extensions/image/__tests__/image.test.ts
Normal file
@@ -0,0 +1,75 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
createEditor,
|
||||
h,
|
||||
p,
|
||||
outlineList,
|
||||
outlineListItem
|
||||
} from "../../../../test-utils/index.js";
|
||||
import { test, expect, describe } from "vitest";
|
||||
import { ImageNode } from "../index.js";
|
||||
import { OutlineList } from "../../outline-list/outline-list.js";
|
||||
import { OutlineListItem } from "../../outline-list-item/outline-list-item.js";
|
||||
|
||||
describe("migration", () => {
|
||||
test(`inline image in paragraph`, async () => {
|
||||
const el = p(["hello", h("img", [], { src: "image.png" }), "world"]);
|
||||
const {
|
||||
builder: { image },
|
||||
editor
|
||||
} = createEditor({
|
||||
initialContent: el.outerHTML,
|
||||
extensions: {
|
||||
image: ImageNode.configure({})
|
||||
}
|
||||
});
|
||||
|
||||
expect(editor.getJSON()).toMatchSnapshot();
|
||||
});
|
||||
|
||||
test(`inline image in outline list`, async () => {
|
||||
const el = outlineList(
|
||||
outlineListItem(["item 1"]),
|
||||
outlineListItem(
|
||||
["hello", h("img", [], { src: "image.png" }), "world"],
|
||||
outlineList(
|
||||
outlineListItem(["sub item 2"]),
|
||||
outlineListItem(["sub item 3"])
|
||||
)
|
||||
),
|
||||
outlineListItem(["item 4"])
|
||||
);
|
||||
|
||||
const {
|
||||
builder: { image },
|
||||
editor
|
||||
} = createEditor({
|
||||
initialContent: el.outerHTML,
|
||||
extensions: {
|
||||
outlineList: OutlineList,
|
||||
outlineListItem: OutlineListItem,
|
||||
image: ImageNode
|
||||
}
|
||||
});
|
||||
|
||||
expect(editor.getJSON()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -131,39 +131,6 @@ export const ImageNode = Node.create<ImageOptions>({
|
||||
getAttrs(node) {
|
||||
if (node.querySelectorAll("img").length <= 0) return false;
|
||||
return null;
|
||||
},
|
||||
getContent: (dom, schema) => {
|
||||
const wrapper = document.createElement("div");
|
||||
let buffer = "";
|
||||
|
||||
const flushBuffer = () => {
|
||||
if (buffer.trim().length > 0) {
|
||||
const pEl = document.createElement("p");
|
||||
pEl.innerHTML = buffer;
|
||||
wrapper.appendChild(pEl);
|
||||
buffer = "";
|
||||
}
|
||||
};
|
||||
|
||||
for (const child of dom.childNodes) {
|
||||
if (
|
||||
child.nodeType === globalThis.Node.ELEMENT_NODE &&
|
||||
(child as HTMLElement).tagName === "IMG"
|
||||
) {
|
||||
flushBuffer();
|
||||
wrapper.appendChild(child);
|
||||
} else {
|
||||
if (child.nodeType === globalThis.Node.ELEMENT_NODE) {
|
||||
buffer += (child as HTMLElement).outerHTML;
|
||||
} else if (child.nodeType === globalThis.Node.TEXT_NODE) {
|
||||
buffer += child.textContent;
|
||||
}
|
||||
}
|
||||
}
|
||||
flushBuffer();
|
||||
|
||||
const parser = DOMParser.fromSchema(schema);
|
||||
return parser.parse(wrapper).content;
|
||||
}
|
||||
},
|
||||
{
|
||||
|
||||
@@ -0,0 +1,130 @@
|
||||
// Vitest Snapshot v1, https://vitest.dev/guide/snapshot.html
|
||||
|
||||
exports[`outline list item > code block in outline list item 1`] = `
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "item 1",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "hello",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"caretPosition": undefined,
|
||||
"id": "codeblock-test-id-123456",
|
||||
"indentLength": 2,
|
||||
"indentType": "space",
|
||||
"language": null,
|
||||
"lines": [],
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"text": "const x = 1;",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "codeblock",
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "world",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "sub item 2",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "sub item 3",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
],
|
||||
"type": "outlineList",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
{
|
||||
"attrs": {
|
||||
"collapsed": false,
|
||||
},
|
||||
"content": [
|
||||
{
|
||||
"content": [
|
||||
{
|
||||
"text": "item 4",
|
||||
"type": "text",
|
||||
},
|
||||
],
|
||||
"type": "paragraph",
|
||||
},
|
||||
],
|
||||
"type": "outlineListItem",
|
||||
},
|
||||
],
|
||||
"type": "outlineList",
|
||||
},
|
||||
],
|
||||
"type": "doc",
|
||||
}
|
||||
`;
|
||||
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
This file is part of the Notesnook project (https://notesnook.com/)
|
||||
|
||||
Copyright (C) 2023 Streetwriters (Private) Limited
|
||||
|
||||
This program is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU General Public License as published by
|
||||
the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import {
|
||||
createEditor,
|
||||
h,
|
||||
li,
|
||||
outlineList,
|
||||
outlineListItem
|
||||
} from "../../../../test-utils/index.js";
|
||||
import { test, expect, describe, beforeAll, vi } from "vitest";
|
||||
import { OutlineList } from "../../outline-list/outline-list.js";
|
||||
import { OutlineListItem } from "../outline-list-item.js";
|
||||
import { CodeBlock } from "../../code-block/code-block.js";
|
||||
|
||||
describe("outline list item", () => {
|
||||
beforeAll(() => {
|
||||
vi.mock("nanoid", () => ({
|
||||
nanoid: () => "test-id-123456"
|
||||
}));
|
||||
});
|
||||
|
||||
test(`code block in outline list item`, async () => {
|
||||
const subList = outlineList(
|
||||
outlineListItem(["sub item 2"]),
|
||||
outlineListItem(["sub item 3"])
|
||||
);
|
||||
const listItemWithCodeBlock = li(
|
||||
[
|
||||
h("p", ["hello"]),
|
||||
h("pre", [h("code", ["const x = 1;"])]),
|
||||
h("p", ["world"]),
|
||||
subList
|
||||
],
|
||||
{ "data-type": "outlineListItem" }
|
||||
);
|
||||
const el = outlineList(
|
||||
outlineListItem(["item 1"]),
|
||||
listItemWithCodeBlock,
|
||||
outlineListItem(["item 4"])
|
||||
);
|
||||
|
||||
const {
|
||||
builder: { codeBlock },
|
||||
editor
|
||||
} = createEditor({
|
||||
initialContent: el.outerHTML,
|
||||
extensions: {
|
||||
outlineList: OutlineList,
|
||||
outlineListItem: OutlineListItem,
|
||||
codeBlock: CodeBlock
|
||||
}
|
||||
});
|
||||
|
||||
expect(editor.getJSON()).toMatchSnapshot();
|
||||
});
|
||||
});
|
||||
@@ -25,6 +25,7 @@ import {
|
||||
import { findParentNodeOfTypeClosestToPos } from "../../utils/prosemirror.js";
|
||||
import { OutlineList } from "../outline-list/outline-list.js";
|
||||
import { keybindings, tiptapKeys } from "@notesnook/common";
|
||||
import { Paragraph } from "../paragraph/paragraph.js";
|
||||
|
||||
export interface ListItemOptions {
|
||||
HTMLAttributes: Record<string, unknown>;
|
||||
@@ -52,13 +53,14 @@ export const OutlineListItem = Node.create<ListItemOptions>({
|
||||
};
|
||||
},
|
||||
|
||||
content: "paragraph+ list?",
|
||||
content: "block+",
|
||||
|
||||
defining: true,
|
||||
|
||||
parseHTML() {
|
||||
return [
|
||||
{
|
||||
priority: 100,
|
||||
tag: `li[data-type="${this.name}"]`
|
||||
}
|
||||
];
|
||||
@@ -92,21 +94,37 @@ export const OutlineListItem = Node.create<ListItemOptions>({
|
||||
return true;
|
||||
});
|
||||
},
|
||||
Enter: () => {
|
||||
// const subList = findSublist(editor, this.type);
|
||||
// if (!subList) return this.editor.commands.splitListItem(this.name);
|
||||
|
||||
// const { isCollapsed, subListPos } = subList;
|
||||
|
||||
// if (isCollapsed) {
|
||||
// return this.editor.commands.toggleOutlineCollapse(subListPos, false);
|
||||
// }
|
||||
Enter: ({ editor }) => {
|
||||
const { $anchor } = editor.state.selection;
|
||||
if (
|
||||
$anchor.parent.type.name !== Paragraph.name ||
|
||||
($anchor.parent.type.name === Paragraph.name &&
|
||||
$anchor.node($anchor.depth - 1)?.type.name !== this.type.name)
|
||||
)
|
||||
return false;
|
||||
|
||||
return this.editor.commands.splitListItem(this.name);
|
||||
},
|
||||
Tab: () => this.editor.commands.sinkListItem(this.name),
|
||||
[keybindings.liftListItem.keys]: () =>
|
||||
this.editor.commands.liftListItem(this.name)
|
||||
Tab: ({ editor }) => {
|
||||
const { $anchor } = editor.state.selection;
|
||||
if (
|
||||
$anchor.parent.type.name !== Paragraph.name ||
|
||||
($anchor.parent.type.name === Paragraph.name &&
|
||||
$anchor.node($anchor.depth - 1)?.type.name !== this.type.name)
|
||||
)
|
||||
return false;
|
||||
return this.editor.commands.sinkListItem(this.name);
|
||||
},
|
||||
[keybindings.liftListItem.keys]: ({ editor }) => {
|
||||
const { $anchor } = editor.state.selection;
|
||||
if (
|
||||
$anchor.parent.type.name !== Paragraph.name ||
|
||||
($anchor.parent.type.name === Paragraph.name &&
|
||||
$anchor.node($anchor.depth - 1)?.type.name !== this.type.name)
|
||||
)
|
||||
return false;
|
||||
return this.editor.commands.liftListItem(this.name);
|
||||
}
|
||||
};
|
||||
},
|
||||
|
||||
@@ -124,7 +142,7 @@ export const OutlineListItem = Node.create<ListItemOptions>({
|
||||
|
||||
function onClick(e: MouseEvent | TouchEvent) {
|
||||
if (e instanceof MouseEvent && e.button !== 0) return;
|
||||
if (!(e.target instanceof HTMLParagraphElement)) return;
|
||||
if (!(e.target instanceof HTMLElement)) return;
|
||||
if (!li.classList.contains("nested")) return;
|
||||
|
||||
const pos = typeof getPos === "function" ? getPos() : 0;
|
||||
|
||||
@@ -69,10 +69,7 @@ export function TableComponent(props: ReactNodeViewProps) {
|
||||
/>
|
||||
</DesktopOnly>
|
||||
<SimpleBar autoHide>
|
||||
<Box
|
||||
dir={textDirection}
|
||||
sx={{ "& table": { width: "100% !important" } }}
|
||||
>
|
||||
<Box dir={textDirection}>
|
||||
<table
|
||||
ref={(ref) => {
|
||||
forwardRef?.(ref);
|
||||
|
||||
@@ -30,6 +30,7 @@ const TEXT_DIRECTION_TYPES = [
|
||||
"orderedList",
|
||||
"bulletList",
|
||||
"outlineList",
|
||||
"checkList",
|
||||
"taskList",
|
||||
"table",
|
||||
"blockquote",
|
||||
|
||||
@@ -28,6 +28,7 @@ import {
|
||||
import { useMemo } from "react";
|
||||
import { CodeBlock } from "../../extensions/code-block/index.js";
|
||||
import { strings } from "@notesnook/intl";
|
||||
import { keybindings } from "@notesnook/common";
|
||||
|
||||
const defaultLevels = [1, 2, 3, 4, 5, 6] as const;
|
||||
|
||||
@@ -70,7 +71,7 @@ function toMenuItems(
|
||||
key: `heading-${level}`,
|
||||
title: toolbarLocation === "bottom" ? `H${level}` : strings.heading(level),
|
||||
isChecked: level === currentHeadingLevel,
|
||||
modifier: `Mod-Alt-${level}`,
|
||||
modifier: keybindings[`insertHeading${level}`].keys,
|
||||
onClick: () =>
|
||||
editor
|
||||
?.chain()
|
||||
@@ -84,7 +85,7 @@ function toMenuItems(
|
||||
type: "button",
|
||||
title: strings.paragraph(),
|
||||
isChecked: !currentHeadingLevel,
|
||||
modifier: `Mod-Alt-0`,
|
||||
modifier: keybindings.insertParagraph.keys,
|
||||
onClick: () => editor.chain().focus().setParagraph().run()
|
||||
};
|
||||
return [paragraph, ...menuItems];
|
||||
|
||||
@@ -76,6 +76,14 @@
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.ProseMirror li:last-of-type {
|
||||
margin-bottom: 0px;
|
||||
}
|
||||
|
||||
.ProseMirror li:first-of-type {
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.ProseMirror ul.tasklist-content-wrapper {
|
||||
padding-left: 0px;
|
||||
}
|
||||
@@ -536,11 +544,11 @@ p > *::selection {
|
||||
.outline-list li.collapsed .outline-list {
|
||||
display: none;
|
||||
}
|
||||
.outline-list li > :first-child {
|
||||
.outline-list li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.outline-list > li > :first-child::before {
|
||||
.outline-list > li::before {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
@@ -560,13 +568,13 @@ p > *::selection {
|
||||
left: -22px;
|
||||
}
|
||||
|
||||
.outline-list li:not(.nested) > :first-child::before {
|
||||
.outline-list li:not(.nested)::before {
|
||||
mask: url(data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxZW0iIGhlaWdodD0iMWVtIiB2aWV3Qm94PSIwIDAgMjQgMjQiPjxwYXRoIGZpbGw9IiM4ODg4ODgiIGQ9Ik0xMiAyQTEwIDEwIDAgMCAwIDIgMTJhMTAgMTAgMCAwIDAgMTAgMTBhMTAgMTAgMCAwIDAgMTAtMTBBMTAgMTAgMCAwIDAgMTIgMloiLz48L3N2Zz4=)
|
||||
no-repeat 50% 50%;
|
||||
scale: 0.4;
|
||||
}
|
||||
|
||||
.outline-list li.collapsed > :first-child::before {
|
||||
.outline-list li.collapsed::before {
|
||||
transform: rotate(-90deg);
|
||||
}
|
||||
|
||||
@@ -638,40 +646,71 @@ p > *::selection {
|
||||
transform: rotate(90deg);
|
||||
}
|
||||
|
||||
.simple-checklist[dir="rtl"] li::after {
|
||||
left: unset;
|
||||
right: -24px;
|
||||
}
|
||||
|
||||
.simple-checklist[dir="rtl"] li.checked::before {
|
||||
left: unset;
|
||||
right: -22px;
|
||||
}
|
||||
|
||||
[dir="rtl"] .taskItemTools { right: unset; left: 0 }
|
||||
|
||||
/* Check list */
|
||||
.ProseMirror ul.simple-checklist {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin-block: 0px !important;
|
||||
padding-inline: 0px !important;
|
||||
padding-inline-start: 24px !important;
|
||||
}
|
||||
|
||||
.ProseMirror ul.simple-checklist > li {
|
||||
display: flex;
|
||||
.ProseMirror li.nested > ul.simple-checklist {
|
||||
padding-inline-start: 15px !important;
|
||||
}
|
||||
|
||||
.ProseMirror ul.simple-checklist > li input {
|
||||
flex: 0 0 auto;
|
||||
margin-right: 0.5rem;
|
||||
user-select: none;
|
||||
height: 1rem;
|
||||
width: 1rem;
|
||||
accent-color: var(--accent);
|
||||
.simple-checklist li {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ProseMirror ul.simple-checklist > li > div {
|
||||
flex: 1 1 auto;
|
||||
.simple-checklist > li::after {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
cursor: pointer;
|
||||
content: "";
|
||||
background-size: 18px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
|
||||
border: 2px solid var(--icon);
|
||||
border-radius: 5px;
|
||||
left: -24px;
|
||||
}
|
||||
|
||||
@media screen and (max-width: 480px) {
|
||||
.ProseMirror ul.simple-checklist > li > input {
|
||||
height: 21px;
|
||||
width: 21px;
|
||||
}
|
||||
.simple-checklist > li.checked::after {
|
||||
border: 2px solid var(--accent);
|
||||
}
|
||||
|
||||
.ProseMirror ul.simple-checklist > li > div {
|
||||
margin-top: 2px;
|
||||
}
|
||||
.simple-checklist > li.checked::before {
|
||||
position: absolute;
|
||||
top: 2px;
|
||||
cursor: pointer;
|
||||
content: "";
|
||||
background-size: 18px;
|
||||
width: 14px;
|
||||
height: 14px;
|
||||
left: -22px;
|
||||
|
||||
background-color: var(--accent);
|
||||
mask: url(data:image/svg+xml;base64,ICA8c3ZnIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyIgdmlld0JveD0iMCAwIDI0IDI0Ij4KICAgIDxwYXRoIGQ9Ik0yMSw3TDksMTlMMy41LDEzLjVMNC45MSwxMi4wOUw5LDE2LjE3TDE5LjU5LDUuNTlMMjEsN1oiLz4KICA8L3N2Zz4K)
|
||||
no-repeat 50% 50%;
|
||||
mask-size: cover;
|
||||
}
|
||||
|
||||
.simple-checklist > li.checked > p {
|
||||
opacity: 0.8;
|
||||
text-decoration-line: line-through;
|
||||
}
|
||||
|
||||
/* Callout */
|
||||
|
||||
@@ -92,3 +92,19 @@ export const p = elem("p");
|
||||
export function text(text: string) {
|
||||
return document.createTextNode(text);
|
||||
}
|
||||
|
||||
export function outlineList(...children: HTMLLIElement[]) {
|
||||
return ul(children, { "data-type": "outlineList" });
|
||||
}
|
||||
|
||||
export function outlineListItem(
|
||||
paragraphChildren: (string | HTMLElement)[],
|
||||
subList?: HTMLUListElement
|
||||
) {
|
||||
const children: HTMLElement[] = [h("p", paragraphChildren)];
|
||||
if (subList) children.push(subList);
|
||||
|
||||
return li(children, {
|
||||
"data-type": "outlineListItem"
|
||||
});
|
||||
}
|
||||
|
||||
@@ -2842,6 +2842,10 @@ msgstr "Filter attachments by filename, type or hash"
|
||||
msgid "Filter languages"
|
||||
msgstr "Filter languages"
|
||||
|
||||
#: src/strings.ts:2594
|
||||
msgid "Finish your purchase in the browser."
|
||||
msgstr "Finish your purchase in the browser."
|
||||
|
||||
#: src/strings.ts:1668
|
||||
msgid "Fix it"
|
||||
msgstr "Fix it"
|
||||
@@ -3028,6 +3032,10 @@ msgstr "Getting recovery codes"
|
||||
msgid "GNU GENERAL PUBLIC LICENSE Version 3"
|
||||
msgstr "GNU GENERAL PUBLIC LICENSE Version 3"
|
||||
|
||||
#: src/strings.ts:2595
|
||||
msgid "Go back"
|
||||
msgstr "Go back"
|
||||
|
||||
#: src/strings.ts:2445
|
||||
msgid "Go back in tab"
|
||||
msgstr "Go back in tab"
|
||||
@@ -3795,8 +3803,8 @@ msgstr "Member since {date}"
|
||||
msgid "Merge cells"
|
||||
msgstr "Merge cells"
|
||||
|
||||
#. placeholder {0}: progress ? `${progress?.collection}` : null
|
||||
#. placeholder {1}: progress ? `(${progress.current}/${progress.total}) ` : null
|
||||
#. placeholder {0}: progress ? `${progress?.collection}` : ""
|
||||
#. placeholder {1}: progress ? `(${progress.current}/${progress.total}) ` : ""
|
||||
#: src/strings.ts:246
|
||||
msgid "Migrating {0} {1}... please wait"
|
||||
msgstr "Migrating {0} {1}... please wait"
|
||||
|
||||
@@ -2831,6 +2831,10 @@ msgstr ""
|
||||
msgid "Filter languages"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2594
|
||||
msgid "Finish your purchase in the browser."
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:1668
|
||||
msgid "Fix it"
|
||||
msgstr ""
|
||||
@@ -3010,6 +3014,10 @@ msgstr ""
|
||||
msgid "GNU GENERAL PUBLIC LICENSE Version 3"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2595
|
||||
msgid "Go back"
|
||||
msgstr ""
|
||||
|
||||
#: src/strings.ts:2445
|
||||
msgid "Go back in tab"
|
||||
msgstr ""
|
||||
@@ -3775,8 +3783,8 @@ msgstr ""
|
||||
msgid "Merge cells"
|
||||
msgstr ""
|
||||
|
||||
#. placeholder {0}: progress ? `${progress?.collection}` : null
|
||||
#. placeholder {1}: progress ? `(${progress.current}/${progress.total}) ` : null
|
||||
#. placeholder {0}: progress ? `${progress?.collection}` : ""
|
||||
#. placeholder {1}: progress ? `(${progress.current}/${progress.total}) ` : ""
|
||||
#: src/strings.ts:246
|
||||
msgid "Migrating {0} {1}... please wait"
|
||||
msgstr ""
|
||||
|
||||
@@ -243,8 +243,8 @@ export const strings = {
|
||||
collection: string;
|
||||
current: number;
|
||||
}) =>
|
||||
t`Migrating ${progress ? `${progress?.collection}` : null} ${
|
||||
progress ? `(${progress.current}/${progress.total}) ` : null
|
||||
t`Migrating ${progress ? `${progress?.collection}` : ""} ${
|
||||
progress ? `(${progress.current}/${progress.total}) ` : ""
|
||||
}... please wait`,
|
||||
migrationError: () =>
|
||||
t`An error occurred while migrating your data. You can logout of your account and try to relogin. However this is not recommended as it may result in some data loss if your data was not synced.`,
|
||||
@@ -1791,7 +1791,7 @@ For example:
|
||||
],
|
||||
shareWithFriendsDesc: () => t`Because where's the fun in nookin' alone?`,
|
||||
notebooksAllCaps: () => t`NOTEBOOKS`,
|
||||
authenticatedAs: (email?: string) => t`Authenticated as ${email}`,
|
||||
authenticatedAs: (email: string) => t`Authenticated as ${email}`,
|
||||
rememberedYourPassword: () => t`Remembered your password?`,
|
||||
chooseRecoveryMethod: () => t`Choose a recovery method`,
|
||||
chooseRecoveryMethodDesc: () => t`How do you want to recover your account?`,
|
||||
@@ -2590,5 +2590,7 @@ Use this if changes from other devices are not appearing on this device. This wi
|
||||
t`You can change your subscription plan from the web app`,
|
||||
announcement: () => t`ANNOUNCEMENT`,
|
||||
cannotChangePlan: () =>
|
||||
t`Your current subscription does not allow changing plans`
|
||||
t`Your current subscription does not allow changing plans`,
|
||||
finishPurchaseInBrowser: () => t`Finish your purchase in the browser.`,
|
||||
goBack: () => t`Go back`
|
||||
};
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
// vite.config.mts
|
||||
import path, { resolve } from "path";
|
||||
import { defineConfig } from "file:///Users/thecodrr/Sources/Repos/notesnook/packages/intl/node_modules/vite/dist/node/index.js";
|
||||
import swc from "file:///Users/thecodrr/Sources/Repos/notesnook/packages/intl/node_modules/vite-plugin-swc-transform/dist/esm/index.js";
|
||||
import dts from "file:///Users/thecodrr/Sources/Repos/notesnook/packages/intl/node_modules/vite-plugin-dts/dist/index.mjs";
|
||||
import { fileURLToPath } from "url";
|
||||
var __vite_injected_original_import_meta_url = "file:///Users/thecodrr/Sources/Repos/notesnook/packages/intl/vite.config.mts";
|
||||
var __filename = fileURLToPath(__vite_injected_original_import_meta_url);
|
||||
var __dirname = path.dirname(__filename);
|
||||
var vite_config_default = defineConfig({
|
||||
plugins: [
|
||||
swc({
|
||||
swcOptions: {
|
||||
sourceMaps: true,
|
||||
jsc: {
|
||||
parser: {
|
||||
syntax: "typescript",
|
||||
tsx: true
|
||||
},
|
||||
baseUrl: __dirname,
|
||||
paths: {
|
||||
"$src/*": ["src/*"]
|
||||
},
|
||||
experimental: {
|
||||
plugins: [
|
||||
[
|
||||
"@lingui/swc-plugin",
|
||||
{
|
||||
runtimeModules: {
|
||||
i18n: ["$src/setup", "i18n"]
|
||||
}
|
||||
}
|
||||
]
|
||||
]
|
||||
}
|
||||
}
|
||||
}
|
||||
}),
|
||||
dts({
|
||||
exclude: ["**/locales/*.json"],
|
||||
rollupTypes: true
|
||||
})
|
||||
],
|
||||
build: {
|
||||
lib: {
|
||||
entry: resolve(__dirname, "src/index.ts"),
|
||||
formats: ["cjs", "es"],
|
||||
fileName(format) {
|
||||
return format === "cjs" ? "index.js" : "index.mjs";
|
||||
}
|
||||
},
|
||||
outDir: resolve(__dirname, "dist")
|
||||
}
|
||||
});
|
||||
export {
|
||||
vite_config_default as default
|
||||
};
|
||||
//# sourceMappingURL=data:application/json;base64,ewogICJ2ZXJzaW9uIjogMywKICAic291cmNlcyI6IFsidml0ZS5jb25maWcubXRzIl0sCiAgInNvdXJjZXNDb250ZW50IjogWyJjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZGlybmFtZSA9IFwiL1VzZXJzL3RoZWNvZHJyL1NvdXJjZXMvUmVwb3Mvbm90ZXNub29rL3BhY2thZ2VzL2ludGxcIjtjb25zdCBfX3ZpdGVfaW5qZWN0ZWRfb3JpZ2luYWxfZmlsZW5hbWUgPSBcIi9Vc2Vycy90aGVjb2Ryci9Tb3VyY2VzL1JlcG9zL25vdGVzbm9vay9wYWNrYWdlcy9pbnRsL3ZpdGUuY29uZmlnLm10c1wiO2NvbnN0IF9fdml0ZV9pbmplY3RlZF9vcmlnaW5hbF9pbXBvcnRfbWV0YV91cmwgPSBcImZpbGU6Ly8vVXNlcnMvdGhlY29kcnIvU291cmNlcy9SZXBvcy9ub3Rlc25vb2svcGFja2FnZXMvaW50bC92aXRlLmNvbmZpZy5tdHNcIjsvKlxuVGhpcyBmaWxlIGlzIHBhcnQgb2YgdGhlIE5vdGVzbm9vayBwcm9qZWN0IChodHRwczovL25vdGVzbm9vay5jb20vKVxuXG5Db3B5cmlnaHQgKEMpIDIwMjMgU3RyZWV0d3JpdGVycyAoUHJpdmF0ZSkgTGltaXRlZFxuXG5UaGlzIHByb2dyYW0gaXMgZnJlZSBzb2Z0d2FyZTogeW91IGNhbiByZWRpc3RyaWJ1dGUgaXQgYW5kL29yIG1vZGlmeVxuaXQgdW5kZXIgdGhlIHRlcm1zIG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBhcyBwdWJsaXNoZWQgYnlcbnRoZSBGcmVlIFNvZnR3YXJlIEZvdW5kYXRpb24sIGVpdGhlciB2ZXJzaW9uIDMgb2YgdGhlIExpY2Vuc2UsIG9yXG4oYXQgeW91ciBvcHRpb24pIGFueSBsYXRlciB2ZXJzaW9uLlxuXG5UaGlzIHByb2dyYW0gaXMgZGlzdHJpYnV0ZWQgaW4gdGhlIGhvcGUgdGhhdCBpdCB3aWxsIGJlIHVzZWZ1bCxcbmJ1dCBXSVRIT1VUIEFOWSBXQVJSQU5UWTsgd2l0aG91dCBldmVuIHRoZSBpbXBsaWVkIHdhcnJhbnR5IG9mXG5NRVJDSEFOVEFCSUxJVFkgb3IgRklUTkVTUyBGT1IgQSBQQVJUSUNVTEFSIFBVUlBPU0UuICBTZWUgdGhlXG5HTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZSBmb3IgbW9yZSBkZXRhaWxzLlxuXG5Zb3Ugc2hvdWxkIGhhdmUgcmVjZWl2ZWQgYSBjb3B5IG9mIHRoZSBHTlUgR2VuZXJhbCBQdWJsaWMgTGljZW5zZVxuYWxvbmcgd2l0aCB0aGlzIHByb2dyYW0uICBJZiBub3QsIHNlZSA8aHR0cDovL3d3dy5nbnUub3JnL2xpY2Vuc2VzLz4uXG4qL1xuXG5pbXBvcnQgcGF0aCwgeyByZXNvbHZlIH0gZnJvbSBcInBhdGhcIjtcbmltcG9ydCB7IGRlZmluZUNvbmZpZyB9IGZyb20gXCJ2aXRlXCI7XG5pbXBvcnQgc3djIGZyb20gXCJ2aXRlLXBsdWdpbi1zd2MtdHJhbnNmb3JtXCI7XG5pbXBvcnQgZHRzIGZyb20gXCJ2aXRlLXBsdWdpbi1kdHNcIjtcbmltcG9ydCB7IGZpbGVVUkxUb1BhdGggfSBmcm9tIFwidXJsXCI7XG5cbmNvbnN0IF9fZmlsZW5hbWUgPSBmaWxlVVJMVG9QYXRoKGltcG9ydC5tZXRhLnVybCk7XG5jb25zdCBfX2Rpcm5hbWUgPSBwYXRoLmRpcm5hbWUoX19maWxlbmFtZSk7XG5cbmV4cG9ydCBkZWZhdWx0IGRlZmluZUNvbmZpZyh7XG4gIHBsdWdpbnM6IFtcbiAgICBzd2Moe1xuICAgICAgc3djT3B0aW9uczoge1xuICAgICAgICBzb3VyY2VNYXBzOiB0cnVlLFxuICAgICAgICBqc2M6IHtcbiAgICAgICAgICBwYXJzZXI6IHtcbiAgICAgICAgICAgIHN5bnRheDogXCJ0eXBlc2NyaXB0XCIsXG4gICAgICAgICAgICB0c3g6IHRydWVcbiAgICAgICAgICB9LFxuICAgICAgICAgIGJhc2VVcmw6IF9fZGlybmFtZSxcbiAgICAgICAgICBwYXRoczoge1xuICAgICAgICAgICAgXCIkc3JjLypcIjogW1wic3JjLypcIl1cbiAgICAgICAgICB9LFxuICAgICAgICAgIGV4cGVyaW1lbnRhbDoge1xuICAgICAgICAgICAgcGx1Z2luczogW1xuICAgICAgICAgICAgICBbXG4gICAgICAgICAgICAgICAgXCJAbGluZ3VpL3N3Yy1wbHVnaW5cIixcbiAgICAgICAgICAgICAgICB7XG4gICAgICAgICAgICAgICAgICBydW50aW1lTW9kdWxlczoge1xuICAgICAgICAgICAgICAgICAgICBpMThuOiBbXCIkc3JjL3NldHVwXCIsIFwiaTE4blwiXVxuICAgICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgXVxuICAgICAgICAgICAgXVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0pLFxuICAgIGR0cyh7XG4gICAgICBleGNsdWRlOiBbXCIqKi9sb2NhbGVzLyouanNvblwiXSxcbiAgICAgIHJvbGx1cFR5cGVzOiB0cnVlXG4gICAgfSlcbiAgXSxcbiAgYnVpbGQ6IHtcbiAgICBsaWI6IHtcbiAgICAgIGVudHJ5OiByZXNvbHZlKF9fZGlybmFtZSwgXCJzcmMvaW5kZXgudHNcIiksXG4gICAgICBmb3JtYXRzOiBbXCJjanNcIiwgXCJlc1wiXSxcbiAgICAgIGZpbGVOYW1lKGZvcm1hdCkge1xuICAgICAgICByZXR1cm4gZm9ybWF0ID09PSBcImNqc1wiID8gXCJpbmRleC5qc1wiIDogXCJpbmRleC5tanNcIjtcbiAgICAgIH1cbiAgICB9LFxuICAgIG91dERpcjogcmVzb2x2ZShfX2Rpcm5hbWUsIFwiZGlzdFwiKVxuICB9XG59KTtcbiJdLAogICJtYXBwaW5ncyI6ICI7QUFtQkEsT0FBTyxRQUFRLGVBQWU7QUFDOUIsU0FBUyxvQkFBb0I7QUFDN0IsT0FBTyxTQUFTO0FBQ2hCLE9BQU8sU0FBUztBQUNoQixTQUFTLHFCQUFxQjtBQXZCcUwsSUFBTSwyQ0FBMkM7QUF5QnBRLElBQU0sYUFBYSxjQUFjLHdDQUFlO0FBQ2hELElBQU0sWUFBWSxLQUFLLFFBQVEsVUFBVTtBQUV6QyxJQUFPLHNCQUFRLGFBQWE7QUFBQSxFQUMxQixTQUFTO0FBQUEsSUFDUCxJQUFJO0FBQUEsTUFDRixZQUFZO0FBQUEsUUFDVixZQUFZO0FBQUEsUUFDWixLQUFLO0FBQUEsVUFDSCxRQUFRO0FBQUEsWUFDTixRQUFRO0FBQUEsWUFDUixLQUFLO0FBQUEsVUFDUDtBQUFBLFVBQ0EsU0FBUztBQUFBLFVBQ1QsT0FBTztBQUFBLFlBQ0wsVUFBVSxDQUFDLE9BQU87QUFBQSxVQUNwQjtBQUFBLFVBQ0EsY0FBYztBQUFBLFlBQ1osU0FBUztBQUFBLGNBQ1A7QUFBQSxnQkFDRTtBQUFBLGdCQUNBO0FBQUEsa0JBQ0UsZ0JBQWdCO0FBQUEsb0JBQ2QsTUFBTSxDQUFDLGNBQWMsTUFBTTtBQUFBLGtCQUM3QjtBQUFBLGdCQUNGO0FBQUEsY0FDRjtBQUFBLFlBQ0Y7QUFBQSxVQUNGO0FBQUEsUUFDRjtBQUFBLE1BQ0Y7QUFBQSxJQUNGLENBQUM7QUFBQSxJQUNELElBQUk7QUFBQSxNQUNGLFNBQVMsQ0FBQyxtQkFBbUI7QUFBQSxNQUM3QixhQUFhO0FBQUEsSUFDZixDQUFDO0FBQUEsRUFDSDtBQUFBLEVBQ0EsT0FBTztBQUFBLElBQ0wsS0FBSztBQUFBLE1BQ0gsT0FBTyxRQUFRLFdBQVcsY0FBYztBQUFBLE1BQ3hDLFNBQVMsQ0FBQyxPQUFPLElBQUk7QUFBQSxNQUNyQixTQUFTLFFBQVE7QUFDZixlQUFPLFdBQVcsUUFBUSxhQUFhO0FBQUEsTUFDekM7QUFBQSxJQUNGO0FBQUEsSUFDQSxRQUFRLFFBQVEsV0FBVyxNQUFNO0FBQUEsRUFDbkM7QUFDRixDQUFDOyIsCiAgIm5hbWVzIjogW10KfQo=
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup-node src/index.ts",
|
||||
"build": "tsdown src/index.ts",
|
||||
"prepublishOnly": "npm run build",
|
||||
"watch": "npm run build -- --watch"
|
||||
},
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
"postbuild": "node scripts/postbuild.mjs",
|
||||
"prepublishOnly": "npm run build && npm run test",
|
||||
"postinstall": "patch-package",
|
||||
"build": "tsup-node src/browser.ts src/node.ts",
|
||||
"build": "tsdown src/browser.ts src/node.ts",
|
||||
"watch": "npm run build -- --watch"
|
||||
},
|
||||
"license": "GPL-3.0-or-later",
|
||||
|
||||
@@ -16,7 +16,7 @@
|
||||
}
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup-node src/index.ts",
|
||||
"build": "tsdown src/index.ts",
|
||||
"prepublishOnly": "npm run build",
|
||||
"watch": "npm run build -- --watch"
|
||||
},
|
||||
|
||||
@@ -20,6 +20,7 @@ import "isomorphic-fetch";
|
||||
import { mkdir, writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import { existsSync } from "fs";
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
@@ -36,6 +37,8 @@ async function main() {
|
||||
await mkdir(THEMES_DIRECTORY, { recursive: true });
|
||||
|
||||
for (const themeId of DEFAULT_THEMES) {
|
||||
const themePath = path.join(THEMES_DIRECTORY, `${themeId}.json`);
|
||||
if (existsSync(themePath)) continue;
|
||||
console.log("Getting", themeId);
|
||||
|
||||
const BASE_URL = `https://raw.githubusercontent.com/streetwriters/notesnook-themes/main/themes/${themeId}/v${THEME_COMPATIBILITY_VERSION}`;
|
||||
|
||||
@@ -46,8 +46,8 @@
|
||||
"react-dom": ">=18"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "tsup-node src/index.ts",
|
||||
"build": "tsdown src/index.ts",
|
||||
"prepublishOnly": "npm run build",
|
||||
"watch": "npm run build -- --watch"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,11 @@ const TSC =
|
||||
? path.join(__dirname, "..", "node_modules", ".bin", "tsc.cmd")
|
||||
: path.join(__dirname, "..", "node_modules", ".bin", "tsc");
|
||||
|
||||
const TSCGO =
|
||||
process.platform === "win32"
|
||||
? path.join(__dirname, "..", "node_modules", ".bin", "tsgo.cmd")
|
||||
: path.join(__dirname, "..", "node_modules", ".bin", "tsgo");
|
||||
|
||||
const esmPackageJson = {
|
||||
type: "module"
|
||||
};
|
||||
@@ -62,7 +67,7 @@ await Promise.all([
|
||||
IS_WATCH ? "--watch" : ""
|
||||
),
|
||||
cmd(
|
||||
TSC,
|
||||
TSCGO,
|
||||
"--emitDeclarationOnly",
|
||||
"--outDir",
|
||||
"dist/types",
|
||||
@@ -78,9 +83,10 @@ await Promise.all([
|
||||
)
|
||||
]);
|
||||
|
||||
function cmd(...command) {
|
||||
async function cmd(...command) {
|
||||
let p = spawn(command[0], command.slice(1), { shell: true });
|
||||
return new Promise((resolveFunc) => {
|
||||
console.time(command.join(" "));
|
||||
await new Promise((resolveFunc) => {
|
||||
p.stdout.on("data", (x) => {
|
||||
process.stdout.write(x.toString());
|
||||
});
|
||||
@@ -88,8 +94,9 @@ function cmd(...command) {
|
||||
process.stderr.write(x.toString());
|
||||
});
|
||||
p.on("exit", (code) => {
|
||||
console.log(command.join(" "), "exited with code", code);
|
||||
// console.log(command.join(" "), "exited with code", code);
|
||||
resolveFunc(code);
|
||||
});
|
||||
});
|
||||
console.timeEnd(command.join(" "));
|
||||
}
|
||||
|
||||
@@ -18,189 +18,352 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { spawn } from "child_process";
|
||||
import { fdir } from "fdir";
|
||||
import { existsSync, readFileSync, writeFileSync } from "fs";
|
||||
import { readFile } from "fs/promises";
|
||||
import { existsSync, readFileSync } from "fs";
|
||||
import { glob, readFile, rename, stat, writeFile } from "fs/promises";
|
||||
import path from "path";
|
||||
import { fileURLToPath } from "url";
|
||||
import parser from "yargs-parser";
|
||||
import { performance } from "perf_hooks";
|
||||
import { createHash } from "crypto";
|
||||
|
||||
const args = parser(process.argv, {
|
||||
alias: { force: ["-f"], verbose: ["-v"] }
|
||||
});
|
||||
const isVerbose = process.env.CI || args.verbose;
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
const config = JSON.parse(
|
||||
readFileSync(path.join(__dirname, "..", "package.json"), "utf-8")
|
||||
).taskRunner;
|
||||
const cache = JSON.parse(
|
||||
existsSync(path.join(__dirname, "..", ".taskcache"))
|
||||
? readFileSync(path.join(__dirname, "..", ".taskcache"), "utf-8")
|
||||
: "{}"
|
||||
);
|
||||
|
||||
let [project, ...taskParts] = process.argv.slice(2)[0].split(":");
|
||||
const task = taskParts.join(":");
|
||||
|
||||
const allPackages = (
|
||||
await new fdir()
|
||||
.onlyDirs()
|
||||
.withMaxDepth(2)
|
||||
.glob(...config.projects)
|
||||
.crawl(".")
|
||||
.withPromise()
|
||||
).slice(4);
|
||||
|
||||
for (const pkg of allPackages) {
|
||||
if (isPackage(pkg, project)) {
|
||||
project = pkg;
|
||||
break;
|
||||
const args = { _: [], exclude: [], force: false, verbose: false, all: false };
|
||||
const shortFlags = { f: "force", v: "verbose", a: "all", e: "exclude" };
|
||||
for (let i = 2; i < process.argv.length; i++) {
|
||||
const arg = process.argv[i];
|
||||
if (!arg.startsWith("-")) args._.push(arg);
|
||||
else {
|
||||
const isLong = arg.startsWith("--");
|
||||
const [key, value] = isLong ? arg.split("=") : [arg[1], null];
|
||||
const flag = isLong ? key.slice(2) : shortFlags[key];
|
||||
if (!args[flag]) args._.push(arg);
|
||||
else if (Array.isArray(args[flag]))
|
||||
args[flag] = value
|
||||
? value.split(",")
|
||||
: process.argv[++i]?.split(",") || [];
|
||||
else if (flag) args[flag] = true;
|
||||
}
|
||||
}
|
||||
|
||||
const pipeline = await buildExecutionPipeline(
|
||||
config.taskDependencies[task],
|
||||
project
|
||||
);
|
||||
console.log("Found", pipeline.length, "dependencies to run.");
|
||||
for (const item of pipeline) {
|
||||
const checksum = await computeDirectoryChecksum(item.dep);
|
||||
if (checksum === cache[item.dep + ":" + item.cmd]) continue;
|
||||
|
||||
await runScript(item.cmd, item.dep);
|
||||
|
||||
cache[item.dep + ":" + item.cmd] = checksum;
|
||||
if (!args._.length) {
|
||||
console.error("Missing required argument: package:task");
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
await runScript(task, project);
|
||||
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
||||
const root = path.join(__dirname, "..");
|
||||
const isVerbose = !!(process.env.CI || args.verbose);
|
||||
const rootPkg = readJson(path.join(root, "package.json"));
|
||||
const config = rootPkg.taskRunner || { projects: ["packages/*"], tasks: [] };
|
||||
const cachePath = path.join(root, ".taskcache");
|
||||
const [project, ...taskParts] = args.all
|
||||
? [null, ...args._[0].split(":")]
|
||||
: args._[0].split(":");
|
||||
const cmd = taskParts.join(":");
|
||||
const pkgCache = new Map();
|
||||
const depMemo = new Map();
|
||||
|
||||
writeFileSync(
|
||||
path.join(__dirname, "..", ".taskcache"),
|
||||
JSON.stringify(cache, null, 2)
|
||||
);
|
||||
|
||||
async function runScript(command, pkg) {
|
||||
console.log(`Running "${command}" for ${pkg}`);
|
||||
|
||||
return new Promise((resolve, reject) => {
|
||||
const child = spawn("npm", ["run", command], {
|
||||
cwd: pkg,
|
||||
stdio: isVerbose ? "inherit" : "pipe",
|
||||
shell: true
|
||||
});
|
||||
|
||||
child.on("exit", (code) => {
|
||||
if (code === 0) {
|
||||
resolve();
|
||||
} else {
|
||||
reject(new Error(`Command failed with exit code ${code}`));
|
||||
}
|
||||
});
|
||||
|
||||
child.on("error", (err) => {
|
||||
reject(err);
|
||||
});
|
||||
});
|
||||
const allPkgs = await findPkgs();
|
||||
const task = config.tasks?.find((t) => t.commands?.includes(cmd));
|
||||
if (!task) {
|
||||
console.error(`Task "${cmd}" not found in taskRunner config.`);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
async function buildExecutionPipeline(commands, pkg) {
|
||||
if (commands.length === 0) return [];
|
||||
const resolvedPkgs = (
|
||||
await Promise.all(
|
||||
task.dependencies.flatMap((dep) =>
|
||||
allPkgs.map((pkg) => resolvePkg(dep, pkg))
|
||||
)
|
||||
)
|
||||
).filter(Boolean);
|
||||
|
||||
const executionPipeline = [];
|
||||
const deps = await findDependencies(pkg);
|
||||
for (const dep of deps) {
|
||||
if (executionPipeline.some((item) => item.dep === dep)) continue;
|
||||
|
||||
const pipeline = await buildExecutionPipeline(commands, dep);
|
||||
for (const item of pipeline) {
|
||||
if (executionPipeline.some((i) => i.dep === item.dep)) continue;
|
||||
executionPipeline.push(item);
|
||||
}
|
||||
|
||||
const json = JSON.parse(
|
||||
readFileSync(path.join(dep, "package.json"), "utf-8")
|
||||
);
|
||||
for (const cmd of commands) {
|
||||
if (json.scripts && json.scripts[cmd]) {
|
||||
executionPipeline.push({
|
||||
cmd,
|
||||
dep
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return executionPipeline;
|
||||
let cache = {};
|
||||
try {
|
||||
cache = existsSync(cachePath) ? readJson(cachePath) : {};
|
||||
} catch {
|
||||
if (isVerbose) console.warn("Failed to parse .taskcache");
|
||||
}
|
||||
|
||||
function isPackage(pkg, name) {
|
||||
const json = JSON.parse(
|
||||
readFileSync(path.join(pkg, "package.json"), "utf-8")
|
||||
);
|
||||
return json.name === name;
|
||||
}
|
||||
|
||||
async function findDependencies(scope) {
|
||||
function readPkg(pkgPath) {
|
||||
const key = path.resolve(pkgPath);
|
||||
if (pkgCache.has(key)) return pkgCache.get(key);
|
||||
try {
|
||||
const packageJsonPath = path.join(scope, "package.json");
|
||||
const packageJson = JSON.parse(await readFile(packageJsonPath, "utf-8"));
|
||||
const json = readJson(path.join(pkgPath, "package.json"));
|
||||
pkgCache.set(key, json);
|
||||
return json;
|
||||
} catch {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
const dependencies = new Set([
|
||||
...filterDependencies(scope, packageJson.dependencies),
|
||||
...filterDependencies(scope, packageJson.devDependencies),
|
||||
...filterDependencies(scope, packageJson.optionalDependencies),
|
||||
...filterDependencies(scope, packageJson.peerDependencies)
|
||||
]);
|
||||
function readJson(jsonPath) {
|
||||
return JSON.parse(readFileSync(jsonPath, "utf-8"));
|
||||
}
|
||||
|
||||
for (const dependency of dependencies) {
|
||||
(await findDependencies(dependency)).forEach((v) => dependencies.add(v));
|
||||
}
|
||||
function getPkgName(pkgPath) {
|
||||
return readPkg(pkgPath)?.name || path.basename(pkgPath);
|
||||
}
|
||||
|
||||
return Array.from(dependencies.values());
|
||||
} catch (e) {
|
||||
console.error("Failed to find dependencies for", scope, "Error:", e);
|
||||
function isPkg(path, name) {
|
||||
const pkgName = getPkgName(path);
|
||||
return pkgName === name || pkgName.endsWith(`/${name}`);
|
||||
}
|
||||
|
||||
async function findPkgs() {
|
||||
const pkgs = [];
|
||||
for await (const entry of glob(config.projects)) {
|
||||
const pkgPath = path.join(root, entry);
|
||||
if (existsSync(path.join(pkgPath, "package.json")))
|
||||
pkgs.push(path.resolve(pkgPath));
|
||||
}
|
||||
return pkgs;
|
||||
}
|
||||
|
||||
function filterDeps(base, deps) {
|
||||
if (!deps) return [];
|
||||
let filteredDeps = [];
|
||||
for (const [key, value] of Object.entries(deps))
|
||||
if (key.startsWith("@notesnook/") && value?.startsWith("file:"))
|
||||
filteredDeps.push(path.resolve(base, value.slice(5)));
|
||||
return filteredDeps;
|
||||
}
|
||||
|
||||
async function findDeps(scope) {
|
||||
const key = path.resolve(scope);
|
||||
if (depMemo.has(key)) return depMemo.get(key);
|
||||
const pkg = readPkg(scope);
|
||||
if (!pkg) {
|
||||
depMemo.set(key, []);
|
||||
return [];
|
||||
}
|
||||
const deps = new Set(
|
||||
filterDeps(scope, { ...pkg.dependencies, ...pkg.devDependencies })
|
||||
);
|
||||
for (const d of deps) for (const c of await findDeps(d)) deps.add(c);
|
||||
|
||||
const result = Array.from(deps);
|
||||
depMemo.set(key, result);
|
||||
return result;
|
||||
}
|
||||
|
||||
function filterDependencies(basePath, dependencies) {
|
||||
if (!dependencies) return [];
|
||||
return Object.entries(dependencies)
|
||||
.filter(
|
||||
([key, value]) =>
|
||||
key.startsWith("@notesnook/") || value.startsWith("file:")
|
||||
)
|
||||
.map(([_, value]) =>
|
||||
path.resolve(path.join(basePath, value.replace("file:", "")))
|
||||
);
|
||||
}
|
||||
|
||||
async function computeDirectoryChecksum(dir) {
|
||||
const exclusions = [
|
||||
"node_modules",
|
||||
".git",
|
||||
"dist",
|
||||
"build",
|
||||
"out",
|
||||
"locales",
|
||||
"coverage"
|
||||
];
|
||||
const crypto = await import("crypto");
|
||||
const hash = crypto.createHash("sha256");
|
||||
const files = (
|
||||
await new fdir()
|
||||
.withFullPaths()
|
||||
.exclude((dir) => exclusions.some((ex) => dir.includes(ex)))
|
||||
.crawl(path.join(dir))
|
||||
.withPromise()
|
||||
).sort();
|
||||
|
||||
for (const filePath of files) {
|
||||
const fileBuffer = await readFile(filePath);
|
||||
hash.update(fileBuffer);
|
||||
async function resolvePkg(command, pkgPath) {
|
||||
const json = readPkg(pkgPath);
|
||||
if (!json?.scripts?.[command]) return null;
|
||||
const deps = await findDeps(pkgPath);
|
||||
const taskDeps = {};
|
||||
for (const dep of deps) {
|
||||
if (readPkg(dep)?.scripts?.[command]) {
|
||||
taskDeps[command] = taskDeps[command] || [];
|
||||
taskDeps[command].push(dep);
|
||||
}
|
||||
}
|
||||
return { path: pkgPath, cmd: command, taskDependencies: taskDeps };
|
||||
}
|
||||
|
||||
async function runScript(command, pkg, opts) {
|
||||
opts = opts || {};
|
||||
const start = performance.now();
|
||||
const name = getPkgName(pkg);
|
||||
try {
|
||||
await new Promise((resolve, reject) => {
|
||||
const verbose = opts.verbose || isVerbose;
|
||||
const child = spawn("npm", ["run", command, ...(opts.args || [])], {
|
||||
cwd: pkg,
|
||||
stdio: verbose ? "inherit" : "pipe",
|
||||
shell: true
|
||||
});
|
||||
let output = "";
|
||||
if (!verbose && child.stdout) {
|
||||
child.stdout.on("data", (data) => (output += data));
|
||||
child.stderr.on("data", (data) => (output += data));
|
||||
}
|
||||
child.once("exit", (code) =>
|
||||
code === 0
|
||||
? resolve()
|
||||
: reject(new Error(`Exit code ${code}${output ? "\n" + output : ""}`))
|
||||
);
|
||||
child.once("error", reject);
|
||||
});
|
||||
console.log(
|
||||
`${name}:${command} took ${(performance.now() - start).toFixed(0)}ms`
|
||||
);
|
||||
} catch (err) {
|
||||
console.error(`${name}:${command} failed:`, err.message);
|
||||
throw err;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizePath(pathStr) {
|
||||
return path.resolve(pathStr).replace(/\/$/, "");
|
||||
}
|
||||
|
||||
async function toBatches(pkgs, cmd) {
|
||||
const batches = [pkgs.filter((pkg) => !pkg.taskDependencies[cmd]?.length)];
|
||||
const remaining = pkgs
|
||||
.filter((pkg) => !!pkg.taskDependencies[cmd]?.length)
|
||||
.slice();
|
||||
|
||||
while (remaining.length > 0) {
|
||||
const batch = [];
|
||||
for (const pkg of remaining.slice()) {
|
||||
if (
|
||||
pkg.taskDependencies[cmd].every((dep) =>
|
||||
batches.some((batch) =>
|
||||
batch.some(
|
||||
(batchPkg) => normalizePath(dep) === normalizePath(batchPkg.path)
|
||||
)
|
||||
)
|
||||
)
|
||||
) {
|
||||
batch.push(pkg);
|
||||
remaining.splice(remaining.indexOf(pkg), 1);
|
||||
}
|
||||
}
|
||||
if (!batch.length) throw new Error("Cyclic dependencies detected");
|
||||
batches.push(batch);
|
||||
}
|
||||
return batches;
|
||||
}
|
||||
|
||||
async function resolveRecursive(cmd, pkg, visited) {
|
||||
visited = visited || new Set();
|
||||
const result = [];
|
||||
const resolved = await resolvePkg(cmd, pkg);
|
||||
if (!resolved) return [];
|
||||
const rp = path.resolve(pkg);
|
||||
if (visited.has(rp)) return [];
|
||||
visited.add(rp);
|
||||
for (const dep of resolved.taskDependencies[cmd] || []) {
|
||||
for (const resolved of await resolveRecursive(cmd, dep, visited)) {
|
||||
if (!result.some((pkg) => pkg.path === resolved.path))
|
||||
result.push(resolved);
|
||||
}
|
||||
}
|
||||
result.push(resolved);
|
||||
return result;
|
||||
}
|
||||
|
||||
const exclusions = new Set([
|
||||
"node_modules",
|
||||
".git",
|
||||
"dist",
|
||||
"build",
|
||||
"out",
|
||||
"locales",
|
||||
"coverage",
|
||||
"__e2e__",
|
||||
"__mocks__",
|
||||
"__tests__",
|
||||
"__benches__",
|
||||
"scripts",
|
||||
"test-artifacts",
|
||||
"output"
|
||||
]);
|
||||
|
||||
async function computeChecksumFast(dir) {
|
||||
const hash = createHash("sha256");
|
||||
for await (const entry of glob(`${dir}/**/**`, {
|
||||
withFileTypes: true,
|
||||
exclude: (entry) => exclusions.has(entry.name)
|
||||
})) {
|
||||
if (entry.isFile()) {
|
||||
const fullPath = path.join(entry.parentPath, entry.name);
|
||||
const fileStat = await stat(fullPath).catch(() => null);
|
||||
if (!fileStat) continue;
|
||||
hash.update(fullPath);
|
||||
hash.update(fileStat.mtimeMs.toString());
|
||||
hash.update(fileStat.size.toString());
|
||||
}
|
||||
}
|
||||
return hash.digest("hex");
|
||||
}
|
||||
|
||||
async function computeChecksumSlow(dir) {
|
||||
const hash = createHash("sha256");
|
||||
const files = [];
|
||||
for await (const entry of glob(`${dir}/**/**`, {
|
||||
withFileTypes: true,
|
||||
exclude: (entry) => exclusions.has(entry.name)
|
||||
})) {
|
||||
if (entry.isFile()) files.push(path.join(entry.parentPath, entry.name));
|
||||
}
|
||||
files.sort();
|
||||
for (const file of files) {
|
||||
hash.update(path.relative(dir, file));
|
||||
hash.update(await readFile(file).catch(() => ""));
|
||||
}
|
||||
return hash.digest("hex");
|
||||
}
|
||||
|
||||
function findKeyInObject(obj, key) {
|
||||
if (!obj || typeof obj !== "object" || Array.isArray(obj)) return;
|
||||
if (key in obj) return obj[key];
|
||||
for (const value of Object.values(obj)) {
|
||||
const found = findKeyInObject(value, key);
|
||||
if (found) return found;
|
||||
}
|
||||
}
|
||||
|
||||
function getBuildFolder(pkgPath) {
|
||||
const pkg = readPkg(pkgPath);
|
||||
if (!pkg) return null;
|
||||
let artifact =
|
||||
pkg.main ||
|
||||
pkg.module ||
|
||||
pkg.types ||
|
||||
pkg.typings ||
|
||||
findKeyInObject(pkg.exports, "default") ||
|
||||
findKeyInObject(pkg.exports, "types");
|
||||
if (!artifact) return null;
|
||||
const dir = path.join(pkgPath, artifact.replace(/^\.\//, "").split("/")[0]);
|
||||
return existsSync(dir) ? dir : null;
|
||||
}
|
||||
|
||||
if (args.all) {
|
||||
console.time("Took");
|
||||
for (const dep of task.dependencies) {
|
||||
for (const batch of await toBatches(resolvedPkgs, dep)) {
|
||||
await Promise.all(
|
||||
batch
|
||||
.filter((pkg) => !args.exclude.some((name) => isPkg(pkg.path, name)))
|
||||
.map((task) => runScript(task.cmd, task.path))
|
||||
);
|
||||
}
|
||||
}
|
||||
console.timeEnd("Took");
|
||||
} else {
|
||||
console.time("Ready in");
|
||||
const pkg = resolvedPkgs.find((candidate) => isPkg(candidate.path, project));
|
||||
if (!pkg) {
|
||||
console.error(`Package "${project}" not found.`);
|
||||
process.exit(1);
|
||||
}
|
||||
for (const dep of task.dependencies) {
|
||||
for (const batch of await toBatches(
|
||||
await resolveRecursive(dep, pkg.path),
|
||||
dep
|
||||
)) {
|
||||
await Promise.all(
|
||||
batch.map(async (item) => {
|
||||
if (item.path === pkg.path) return;
|
||||
const hasBuild = !!getBuildFolder(item.path);
|
||||
const key = item.path + ":" + item.cmd;
|
||||
const [fast, slow] = cache[key]?.split("|") || [];
|
||||
const fastHash = await computeChecksumFast(item.path);
|
||||
if (hasBuild && !args.force && fast === fastHash) return;
|
||||
const slowHash = await computeChecksumSlow(item.path);
|
||||
if (hasBuild && !args.force && slow === slowHash) return;
|
||||
await runScript(item.cmd, item.path);
|
||||
cache[key] = `${fastHash}|${slowHash}`;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
const tmp = cachePath + ".tmp";
|
||||
await writeFile(tmp, JSON.stringify(cache));
|
||||
await rename(tmp, cachePath);
|
||||
console.timeEnd("Ready in");
|
||||
await runScript(cmd, pkg.path, {
|
||||
verbose: true,
|
||||
args: ["--", ...args._.slice(1)]
|
||||
});
|
||||
}
|
||||
|
||||
@@ -3,6 +3,7 @@
|
||||
"target": "es2016",
|
||||
"module": "ESNext",
|
||||
"moduleResolution": "node",
|
||||
"incremental": true,
|
||||
"esModuleInterop": true,
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"strict": true,
|
||||
|
||||
@@ -17,12 +17,11 @@ You should have received a copy of the GNU General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
import { defineConfig } from "tsup";
|
||||
import { defineConfig } from "tsdown";
|
||||
|
||||
export default defineConfig({
|
||||
clean: true,
|
||||
cjsInterop: true,
|
||||
dts: true,
|
||||
splitting: false,
|
||||
format: ["cjs", "esm"]
|
||||
format: ["cjs", "esm"],
|
||||
dts: {
|
||||
tsgo: true
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user