diff options
88 files changed, 956 insertions, 597 deletions
diff --git a/.eslintignore b/.eslintignore index cf31955..01b8bcb 100644 --- a/.eslintignore +++ b/.eslintignore | |||
@@ -1,4 +1,5 @@ | |||
1 | # Logs | 1 | # Logs |
2 | .log/ | ||
2 | logs | 3 | logs |
3 | *.log | 4 | *.log |
4 | 5 | ||
diff --git a/.eslintrc.cjs b/.eslintrc.cjs new file mode 100644 index 0000000..92af738 --- /dev/null +++ b/.eslintrc.cjs | |||
@@ -0,0 +1,126 @@ | |||
1 | const project = [ | ||
2 | './tsconfig.json', | ||
3 | './packages/*/tsconfig.json', | ||
4 | ]; | ||
5 | |||
6 | module.exports = { | ||
7 | root: true, | ||
8 | plugins: [ | ||
9 | '@typescript-eslint', | ||
10 | ], | ||
11 | extends: [ | ||
12 | 'airbnb-base', | ||
13 | 'airbnb-typescript/base', | ||
14 | 'plugin:@typescript-eslint/recommended', | ||
15 | 'plugin:@typescript-eslint/recommended-requiring-type-checking', | ||
16 | ], | ||
17 | env: { | ||
18 | es6: true, | ||
19 | node: true, | ||
20 | browser: false, | ||
21 | jest: true, | ||
22 | }, | ||
23 | parser: '@typescript-eslint/parser', | ||
24 | parserOptions: { | ||
25 | sourceType: 'module', | ||
26 | project, | ||
27 | allowAutomaticSingleRunInference: true, | ||
28 | tsconfigRootDir: __dirname, | ||
29 | warnOnUnsupportedTypeScriptVersion: false, | ||
30 | }, | ||
31 | settings: { | ||
32 | 'import/parsers': { | ||
33 | '@typescript-eslint/parser': ['.ts', '.tsx'], | ||
34 | }, | ||
35 | 'import/resolver': { | ||
36 | typescript: { | ||
37 | alwaysTryTypes: true, | ||
38 | project, | ||
39 | }, | ||
40 | }, | ||
41 | }, | ||
42 | rules: { | ||
43 | 'import/no-unresolved': 'error', | ||
44 | 'import/order': [ | ||
45 | 'error', | ||
46 | { | ||
47 | alphabetize: { | ||
48 | order: 'asc', | ||
49 | }, | ||
50 | 'newlines-between': 'always', | ||
51 | }, | ||
52 | ], | ||
53 | }, | ||
54 | overrides: [ | ||
55 | { | ||
56 | files: [ | ||
57 | '**/stores/**/*.ts', | ||
58 | ], | ||
59 | rules: { | ||
60 | // In a mobx-state-tree action, we assign to the properties of `self` to update the store. | ||
61 | 'no-param-reassign': 'off', | ||
62 | // mobx-state-tree uses empty interfaces to speed up typechecking. | ||
63 | '@typescript-eslint/no-empty-interface': 'off', | ||
64 | }, | ||
65 | }, | ||
66 | { | ||
67 | files: [ | ||
68 | '**/__tests__/*.{ts,tsx}', | ||
69 | '**/*.{spec,test}.{ts,tsx}', | ||
70 | ], | ||
71 | rules: { | ||
72 | // If a non-null assertion fails in a test, the test will also fail anyways. | ||
73 | '@typescript-eslint/no-non-null-assertion': 'off', | ||
74 | // Jest mocks use unbound method references. | ||
75 | '@typescript-eslint/unbound-method': 'off', | ||
76 | }, | ||
77 | }, | ||
78 | { | ||
79 | files: [ | ||
80 | '**/*.js', | ||
81 | ], | ||
82 | rules: { | ||
83 | // ESM requires extensions for imports. | ||
84 | 'import/extensions': [ | ||
85 | 'error', | ||
86 | 'ignorePackages', | ||
87 | ], | ||
88 | }, | ||
89 | }, | ||
90 | { | ||
91 | files: [ | ||
92 | '.electron-builder.config.cjs', | ||
93 | 'config/**/*.{cjs,js}', | ||
94 | 'jest.config.js', | ||
95 | 'scripts/**/*.js', | ||
96 | 'packages/*/*.config.js', | ||
97 | ], | ||
98 | env: { | ||
99 | // Config files are never run in a browser (even in frontend projects). | ||
100 | browser: false, | ||
101 | node: true, | ||
102 | jest: false, | ||
103 | }, | ||
104 | rules: { | ||
105 | // Config files and build scripts are allowed to use devDependencies. | ||
106 | 'import/no-extraneous-dependencies': [ | ||
107 | 'error', | ||
108 | { | ||
109 | devDependencies: true, | ||
110 | }, | ||
111 | ], | ||
112 | // Allow reporting progress to the console from scripts. | ||
113 | 'no-console': 'off', | ||
114 | }, | ||
115 | }, | ||
116 | { | ||
117 | files: [ | ||
118 | 'packages/*/*.config.js', | ||
119 | ], | ||
120 | rules: { | ||
121 | // Allow relative imports of config files from the root package. | ||
122 | 'import/no-relative-packages': 'off', | ||
123 | }, | ||
124 | }, | ||
125 | ], | ||
126 | }; | ||
diff --git a/.eslintrc.json b/.eslintrc.json deleted file mode 100644 index 82f5d58..0000000 --- a/.eslintrc.json +++ /dev/null | |||
@@ -1,191 +0,0 @@ | |||
1 | { | ||
2 | "root": true, | ||
3 | "env": { | ||
4 | "node": true, | ||
5 | "browser": true, | ||
6 | "es2021": true | ||
7 | }, | ||
8 | "extends": [ | ||
9 | "eslint-config-airbnb-typescript", | ||
10 | "plugin:import/recommended", | ||
11 | "plugin:import/typescript" | ||
12 | ], | ||
13 | "parser": "@typescript-eslint/parser", | ||
14 | "parserOptions": { | ||
15 | "ecmaFeatures": { | ||
16 | "jsx": true | ||
17 | }, | ||
18 | "ecmaVersion": 2021, | ||
19 | "project": "./tsconfig.json" | ||
20 | }, | ||
21 | "plugins": [ | ||
22 | "react", | ||
23 | "@typescript-eslint" | ||
24 | ], | ||
25 | "rules": { | ||
26 | "indent": [ | ||
27 | 2, | ||
28 | 2, | ||
29 | { | ||
30 | "SwitchCase": 1 | ||
31 | } | ||
32 | ], | ||
33 | "quotes": [ | ||
34 | "error", | ||
35 | "single" | ||
36 | ], | ||
37 | "linebreak-style": [ | ||
38 | "error", | ||
39 | "unix" | ||
40 | ], | ||
41 | "semi": [ | ||
42 | "error", | ||
43 | "always" | ||
44 | ], | ||
45 | "import/extensions": [ | ||
46 | "error", | ||
47 | "ignorePackages", | ||
48 | { | ||
49 | "js": "always", | ||
50 | "jsx": "always", | ||
51 | "json": "never", | ||
52 | "ts": "never", | ||
53 | "tsx": "never" | ||
54 | } | ||
55 | ], | ||
56 | "import/no-unresolved": [ | ||
57 | "error", | ||
58 | { | ||
59 | "caseSensitive": false | ||
60 | } | ||
61 | ], | ||
62 | "import/no-extraneous-dependencies": [ | ||
63 | "error", | ||
64 | { | ||
65 | // "devDependencies": true, | ||
66 | // "optionalDependencies": true, | ||
67 | // "peerDependencies": true, | ||
68 | "bundledDependencies": true | ||
69 | } | ||
70 | ], | ||
71 | // Best practices | ||
72 | "block-scoped-var": 1, | ||
73 | "complexity": [ | ||
74 | 1, | ||
75 | 4 | ||
76 | ], | ||
77 | "consistent-return": 1, | ||
78 | "curly": 1, | ||
79 | "default-case": 1, | ||
80 | "dot-location": [ | ||
81 | 1, | ||
82 | "property" | ||
83 | ], | ||
84 | "dot-notation": 1, | ||
85 | "eqeqeq": 2, | ||
86 | "guard-for-in": 1, | ||
87 | "no-alert": 2, | ||
88 | "no-caller": 2, | ||
89 | "no-case-declarations": 2, | ||
90 | "no-console": 0, | ||
91 | "no-div-regex": 1, | ||
92 | "no-else-return": 0, | ||
93 | "no-empty": 0, | ||
94 | "no-empty-pattern": 2, | ||
95 | "no-eq-null": 2, | ||
96 | "no-eval": 2, | ||
97 | "no-extend-native": 1, | ||
98 | "no-extra-bind": 1, | ||
99 | "no-fallthrough": 1, | ||
100 | "no-floating-decimal": 1, | ||
101 | "no-implicit-coercion": 1, | ||
102 | "no-implied-eval": 1, | ||
103 | "no-invalid-this": 2, | ||
104 | "no-iterator": 2, | ||
105 | "no-labels": 1, | ||
106 | "no-lone-blocks": 1, | ||
107 | "no-loop-func": 2, | ||
108 | "no-magic-numbers": [ | ||
109 | "error", | ||
110 | { | ||
111 | "ignore": [ | ||
112 | -1, | ||
113 | 0, | ||
114 | 1, | ||
115 | 2, | ||
116 | 100, | ||
117 | 200, | ||
118 | 422, | ||
119 | 3600000, | ||
120 | 1453449120000, | ||
121 | 1453445460000 | ||
122 | ] | ||
123 | } | ||
124 | ], | ||
125 | "no-multi-spaces": 1, | ||
126 | "no-multi-str": 1, | ||
127 | "no-native-reassign": 1, | ||
128 | "no-new-func": 2, | ||
129 | "no-new-wrappers": 2, | ||
130 | "no-new": 1, | ||
131 | "no-octal-escape": 1, | ||
132 | "no-octal": 1, | ||
133 | "no-param-reassign": 1, | ||
134 | "no-process-env": 2, | ||
135 | "no-proto": 2, | ||
136 | "no-redeclare": 1, | ||
137 | "no-return-assign": 2, | ||
138 | "no-script-url": 2, | ||
139 | "no-self-compare": 1, | ||
140 | "no-sequences": 1, | ||
141 | "no-throw-literal": 2, | ||
142 | "no-unused-expressions": [ | ||
143 | 1, | ||
144 | { | ||
145 | "allowTernary": true | ||
146 | } | ||
147 | ], | ||
148 | "no-useless-call": 2, | ||
149 | "no-useless-concat": 1, | ||
150 | "no-void": 2, | ||
151 | "no-warning-comments": 0, | ||
152 | "no-with": 2, | ||
153 | "radix": 1, | ||
154 | "vars-on-top": 0, | ||
155 | "wrap-iife": 2, | ||
156 | "yoda": 0, | ||
157 | "strict": 1, | ||
158 | // Variables | ||
159 | "init-declarations": 0, | ||
160 | "no-catch-shadow": 2, | ||
161 | "no-delete-var": 2, | ||
162 | "no-label-var": 2, | ||
163 | "no-shadow-restricted-names": 2, | ||
164 | "no-shadow": 2, | ||
165 | "no-undef-init": 1, | ||
166 | "no-undef": 2, | ||
167 | "no-undefined": 0, | ||
168 | "no-unused-vars": 2, | ||
169 | "no-use-before-define": 2 | ||
170 | }, | ||
171 | "globals": { | ||
172 | "__dirname": false | ||
173 | }, | ||
174 | "overrides": [ | ||
175 | { | ||
176 | "files": [ | ||
177 | "**/__tests__/*" | ||
178 | ], | ||
179 | "globals": { | ||
180 | "after": false, | ||
181 | "afterEach": false, | ||
182 | "beforeAll": false, | ||
183 | "beforeEach": false, | ||
184 | "describe": false, | ||
185 | "Electron": false, | ||
186 | "expect": false, | ||
187 | "it": false | ||
188 | } | ||
189 | } | ||
190 | ] | ||
191 | } | ||
diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index bf9461e..c522036 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml | |||
@@ -2,35 +2,38 @@ image: node:16.13.1 | |||
2 | 2 | ||
3 | cache: | 3 | cache: |
4 | paths: | 4 | paths: |
5 | - node_modules/ | 5 | - .yarn/cache/ |
6 | - .yarn/cache | ||
7 | 6 | ||
8 | stages: | 7 | stages: |
8 | - code-quality | ||
9 | - test | 9 | - test |
10 | - lint | ||
11 | - build | 10 | - build |
12 | 11 | ||
13 | Run tests: | 12 | default: |
14 | stage: test | ||
15 | before_script: | 13 | before_script: |
16 | - yarn install | 14 | - yarn install --immutable |
15 | |||
16 | lint: | ||
17 | stage: code-quality | ||
17 | script: | 18 | script: |
18 | - yarn test | 19 | - yarn lint --format gitlab |
20 | artifacts: | ||
21 | reports: | ||
22 | codequality: gl-codequality.json | ||
19 | 23 | ||
20 | Run linter and static analyzer: | 24 | typecheck: |
21 | stage: lint | 25 | stage: code-quality |
22 | before_script: | ||
23 | - yarn install | ||
24 | script: | 26 | script: |
25 | - yarn dlx @yarnpkg/doctor | ||
26 | - yarn typecheck | 27 | - yarn typecheck |
27 | - yarn run lint | 28 | |
29 | test: | ||
30 | stage: test | ||
31 | script: | ||
32 | - yarn test | ||
28 | 33 | ||
29 | # TODO: GitlabCI free runners are only for linux - need to investigate for macos and windows artifacts | 34 | # TODO: GitlabCI free runners are only for linux - need to investigate for macos and windows artifacts |
30 | Build the app: | 35 | build: |
31 | stage: build | 36 | stage: build |
32 | before_script: | ||
33 | - yarn install | ||
34 | script: | 37 | script: |
35 | - yarn compile | 38 | - yarn compile |
36 | # TODO: Need to publish the built distributable file | 39 | # TODO: Need to publish the built distributable file |
diff --git a/.yarnrc.yml b/.yarnrc.yml index f83ee48..e8caff1 100644 --- a/.yarnrc.yml +++ b/.yarnrc.yml | |||
@@ -1,13 +1,6 @@ | |||
1 | plugins: | 1 | enableTelemetry: 0 |
2 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs | ||
3 | spec: "@yarnpkg/plugin-interactive-tools" | ||
4 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs | ||
5 | spec: "@yarnpkg/plugin-workspace-tools" | ||
6 | - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs | ||
7 | spec: "@yarnpkg/plugin-typescript" | ||
8 | 2 | ||
9 | logFilters: | 3 | logFilters: |
10 | # Discard incompatible package architecture warnings. | ||
11 | - code: YN0076 | 4 | - code: YN0076 |
12 | level: discard | 5 | level: discard |
13 | 6 | ||
@@ -15,4 +8,18 @@ nmMode: hardlinks-local | |||
15 | 8 | ||
16 | nodeLinker: node-modules | 9 | nodeLinker: node-modules |
17 | 10 | ||
11 | packageExtensions: | ||
12 | eslint-config-airbnb-typescript@*: | ||
13 | peerDependencies: | ||
14 | eslint: "*" | ||
15 | eslint-plugin-import: "*" | ||
16 | |||
17 | plugins: | ||
18 | - path: .yarn/plugins/@yarnpkg/plugin-interactive-tools.cjs | ||
19 | spec: "@yarnpkg/plugin-interactive-tools" | ||
20 | - path: .yarn/plugins/@yarnpkg/plugin-workspace-tools.cjs | ||
21 | spec: "@yarnpkg/plugin-workspace-tools" | ||
22 | - path: .yarn/plugins/@yarnpkg/plugin-typescript.cjs | ||
23 | spec: "@yarnpkg/plugin-typescript" | ||
24 | |||
18 | yarnPath: .yarn/releases/yarn-3.1.1.cjs | 25 | yarnPath: .yarn/releases/yarn-3.1.1.cjs |
@@ -25,6 +25,12 @@ To start working, install all dependencies with | |||
25 | yarn install | 25 | yarn install |
26 | ``` | 26 | ``` |
27 | 27 | ||
28 | If TypeScript complains about missing type definitions, run | ||
29 | |||
30 | ```sh | ||
31 | yarn types | ||
32 | ``` | ||
33 | |||
28 | To start a development instance of Sophie, which will reload on source changes, run | 34 | To start a development instance of Sophie, which will reload on source changes, run |
29 | 35 | ||
30 | ``` sh | 36 | ``` sh |
@@ -49,7 +55,7 @@ To build the application in release mode, run | |||
49 | yarn compile | 55 | yarn compile |
50 | ``` | 56 | ``` |
51 | 57 | ||
52 | If TypeScript complains about missing type definitions, or you want to typecheck the project, run | 58 | To typecheck the project, run |
53 | 59 | ||
54 | ```sh | 60 | ```sh |
55 | yarn typecheck | 61 | yarn typecheck |
diff --git a/config/buildConstants.js b/config/buildConstants.js index 627c895..9083d78 100644 --- a/config/buildConstants.js +++ b/config/buildConstants.js | |||
@@ -1,7 +1,7 @@ | |||
1 | import { readFileSync } from 'fs'; | 1 | import { readFileSync } from 'fs'; |
2 | import { join } from 'path'; | 2 | import { join } from 'path'; |
3 | 3 | ||
4 | import { fileURLToDirname } from './utils.js'; | 4 | import fileURLToDirname from './fileURLToDirname.js'; |
5 | 5 | ||
6 | const thisDir = fileURLToDirname(import.meta.url); | 6 | const thisDir = fileURLToDirname(import.meta.url); |
7 | 7 | ||
@@ -9,6 +9,8 @@ const thisDir = fileURLToDirname(import.meta.url); | |||
9 | // so we have to use the synchronous filesystem API. | 9 | // so we have to use the synchronous filesystem API. |
10 | const electronVendorsJson = readFileSync(join(thisDir, '../.electron-vendors.cache.json'), 'utf8'); | 10 | const electronVendorsJson = readFileSync(join(thisDir, '../.electron-vendors.cache.json'), 'utf8'); |
11 | 11 | ||
12 | /** @type {{ chrome: number; node: number; }} */ | ||
13 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment | ||
12 | const { chrome: chromeVersion, node: nodeVersion } = JSON.parse(electronVendorsJson); | 14 | const { chrome: chromeVersion, node: nodeVersion } = JSON.parse(electronVendorsJson); |
13 | 15 | ||
14 | /** @type {string} */ | 16 | /** @type {string} */ |
diff --git a/config/utils.js b/config/fileURLToDirname.js index d3e13d9..70654cb 100644 --- a/config/utils.js +++ b/config/fileURLToDirname.js | |||
@@ -5,6 +5,6 @@ import { fileURLToPath } from 'url'; | |||
5 | * @param {string} url | 5 | * @param {string} url |
6 | * @returns {string} | 6 | * @returns {string} |
7 | */ | 7 | */ |
8 | export function fileURLToDirname(url) { | 8 | export default function fileURLToDirname(url) { |
9 | return dirname(fileURLToPath(url)); | 9 | return dirname(fileURLToPath(url)); |
10 | } | 10 | } |
diff --git a/config/esbuildConfig.js b/config/getEsbuildConfig.js index 93419fb..b338d68 100644 --- a/config/esbuildConfig.js +++ b/config/getEsbuildConfig.js | |||
@@ -15,7 +15,7 @@ const modeString = JSON.stringify(mode); | |||
15 | * @param {Record<string, unknown>} [extraMetaEnvVars] | 15 | * @param {Record<string, unknown>} [extraMetaEnvVars] |
16 | * @returns {import('esbuild').BuildOptions} | 16 | * @returns {import('esbuild').BuildOptions} |
17 | */ | 17 | */ |
18 | export function getConfig(config, extraMetaEnvVars) { | 18 | export default function getEsbuildConfig(config, extraMetaEnvVars) { |
19 | return { | 19 | return { |
20 | logLevel: 'info', | 20 | logLevel: 'info', |
21 | bundle: true, | 21 | bundle: true, |
diff --git a/config/jest.config.base.js b/config/jest.config.base.js index 2ca021b..463e498 100644 --- a/config/jest.config.base.js +++ b/config/jest.config.base.js | |||
@@ -1,13 +1,13 @@ | |||
1 | import { join } from 'path'; | 1 | import { join } from 'path'; |
2 | 2 | ||
3 | import { fileURLToDirname } from './utils.js'; | 3 | import fileURLToDirname from './fileURLToDirname.js'; |
4 | 4 | ||
5 | const thisDir = fileURLToDirname(import.meta.url); | 5 | const thisDir = fileURLToDirname(import.meta.url); |
6 | 6 | ||
7 | /** @type {import('@jest/types').Config.InitialOptions} */ | 7 | /** @type {import('@jest/types').Config.InitialOptions} */ |
8 | export default { | 8 | export default { |
9 | transform: { | 9 | transform: { |
10 | '\\.tsx?$': join(thisDir, 'jestEsbuildTransform.js'), | 10 | '\\.tsx?$': join(thisDir, 'jestEsbuildTransformer.js'), |
11 | }, | 11 | }, |
12 | extensionsToTreatAsEsm: [ | 12 | extensionsToTreatAsEsm: [ |
13 | '.ts', | 13 | '.ts', |
diff --git a/config/jestEsbuildTransform.js b/config/jestEsbuildTransform.js deleted file mode 100644 index 4bf49e6..0000000 --- a/config/jestEsbuildTransform.js +++ /dev/null | |||
@@ -1,23 +0,0 @@ | |||
1 | import { transform } from 'esbuild'; | ||
2 | |||
3 | import { node } from './buildConstants.js'; | ||
4 | |||
5 | /** @type {import('@jest/transform').AsyncTransformer<undefined>} */ | ||
6 | const transformer = { | ||
7 | canInstrument: false, | ||
8 | async processAsync(source, filePath) { | ||
9 | const { code, map } = await transform(source, { | ||
10 | loader: filePath.endsWith('tsx') ? 'tsx' : 'ts', | ||
11 | sourcefile: filePath, | ||
12 | format: 'esm', | ||
13 | target: node, | ||
14 | sourcemap: true, | ||
15 | }); | ||
16 | return { | ||
17 | code, | ||
18 | map, | ||
19 | }; | ||
20 | }, | ||
21 | }; | ||
22 | |||
23 | export default transformer; | ||
diff --git a/config/jestEsbuildTransformer.js b/config/jestEsbuildTransformer.js new file mode 100644 index 0000000..b6f2fc3 --- /dev/null +++ b/config/jestEsbuildTransformer.js | |||
@@ -0,0 +1,28 @@ | |||
1 | import { transform } from 'esbuild'; | ||
2 | |||
3 | import { node } from './buildConstants.js'; | ||
4 | |||
5 | /** | ||
6 | * @param {string} source | ||
7 | * @param {import('@jest/types').Config.Path} filePath | ||
8 | * @return {Promise<import('@jest/transform').TransformedSource>} | ||
9 | */ | ||
10 | async function processAsync(source, filePath) { | ||
11 | const { code, map } = await transform(source, { | ||
12 | loader: filePath.endsWith('tsx') ? 'tsx' : 'ts', | ||
13 | sourcefile: filePath, | ||
14 | format: 'esm', | ||
15 | target: node, | ||
16 | sourcemap: true, | ||
17 | }); | ||
18 | return { | ||
19 | code, | ||
20 | map, | ||
21 | }; | ||
22 | } | ||
23 | |||
24 | /** @type {import('@jest/transform').AsyncTransformer<void>} */ | ||
25 | export default { | ||
26 | canInstrument: false, | ||
27 | processAsync, | ||
28 | }; | ||
diff --git a/config/tsconfig.base.json b/config/tsconfig.base.json new file mode 100644 index 0000000..255f334 --- /dev/null +++ b/config/tsconfig.base.json | |||
@@ -0,0 +1,19 @@ | |||
1 | { | ||
2 | "compilerOptions": { | ||
3 | "module": "esnext", | ||
4 | "target": "esnext", | ||
5 | "moduleResolution": "node", | ||
6 | "esModuleInterop": true, | ||
7 | "allowSyntheticDefaultImports": true, | ||
8 | "strict": true, | ||
9 | "noImplicitOverride": true, | ||
10 | "noImplicitReturns": true, | ||
11 | "exactOptionalPropertyTypes": true, | ||
12 | "isolatedModules": true, | ||
13 | "skipLibCheck": true, | ||
14 | "checkJs": true, | ||
15 | "lib": [ | ||
16 | "esnext" | ||
17 | ] | ||
18 | } | ||
19 | } | ||
diff --git a/jest.config.js b/jest.config.js index 74e18b7..c631fdd 100644 --- a/jest.config.js +++ b/jest.config.js | |||
@@ -1,8 +1,9 @@ | |||
1 | /** @type {import('ts-jest').InitialOptionsTsJest} */ | 1 | /** @type {import('@jest/types').Config.InitialOptions} */ |
2 | export default { | 2 | export default { |
3 | projects: [ | 3 | projects: [ |
4 | '<rootDir>/packages/*', | 4 | '<rootDir>/packages/*', |
5 | ], | 5 | ], |
6 | /** @type {'babel' | 'v8'} */ | ||
6 | coverageProvider: 'v8', | 7 | coverageProvider: 'v8', |
7 | collectCoverageFrom: [ | 8 | collectCoverageFrom: [ |
8 | 'src/**/*.{ts,tsx}', | 9 | 'src/**/*.{ts,tsx}', |
diff --git a/package.json b/package.json index 99cc7a2..f632a8c 100644 --- a/package.json +++ b/package.json | |||
@@ -19,7 +19,7 @@ | |||
19 | "type": "module", | 19 | "type": "module", |
20 | "main": "packages/main/dist/index.cjs", | 20 | "main": "packages/main/dist/index.cjs", |
21 | "scripts": { | 21 | "scripts": { |
22 | "clean": "rimraf dist packages/*/dist packages/*/tsconfig.tsbuildinfo .vite", | 22 | "clean": "rimraf coverage dist packages/*/dist packages/*/*.tsbuildinfo .vite", |
23 | "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", | 23 | "test": "node --experimental-vm-modules node_modules/jest/bin/jest.js", |
24 | "build": "node scripts/build.js", | 24 | "build": "node scripts/build.js", |
25 | "precompile": "cross-env MODE=production yarn run build", | 25 | "precompile": "cross-env MODE=production yarn run build", |
@@ -27,8 +27,12 @@ | |||
27 | "compile:electron-builder": "electron-builder build --config .electron-builder.config.cjs --dir", | 27 | "compile:electron-builder": "electron-builder build --config .electron-builder.config.cjs --dir", |
28 | "watch": "node scripts/watch.js", | 28 | "watch": "node scripts/watch.js", |
29 | "watch:test": "yarn test --watch", | 29 | "watch:test": "yarn test --watch", |
30 | "typecheck": "yarn workspaces foreach -vpt run typecheck", | 30 | "lint": "yarn types && eslint .", |
31 | "lint": "eslint \"{config,packages,scripts}/**/*.{js,jsx,ts,tsx}\" --quiet", | 31 | "typecheck": "yarn types && yarn workspaces foreach -vp run typecheck:workspace", |
32 | "typecheck:workspace": "yarn g:typecheck", | ||
33 | "g:typecheck": "cd $INIT_CWD && tsc", | ||
34 | "types": "yarn workspaces foreach -vpt run types", | ||
35 | "g:types": "cd $INIT_CWD && tsc -b tsconfig.build.json", | ||
32 | "update-electron-vendors": "node scripts/update-electron-vendors.js", | 36 | "update-electron-vendors": "node scripts/update-electron-vendors.js", |
33 | "main": "yarn workspace @sophie/main", | 37 | "main": "yarn workspace @sophie/main", |
34 | "preload": "yarn workspace @sophie/preload", | 38 | "preload": "yarn workspace @sophie/preload", |
@@ -53,9 +57,15 @@ | |||
53 | "electron-builder": "^22.14.12", | 57 | "electron-builder": "^22.14.12", |
54 | "esbuild": "^0.14.11", | 58 | "esbuild": "^0.14.11", |
55 | "eslint": "^8.6.0", | 59 | "eslint": "^8.6.0", |
60 | "eslint-config-airbnb": "^19.0.4", | ||
61 | "eslint-config-airbnb-base": "^15.0.0", | ||
56 | "eslint-config-airbnb-typescript": "^16.1.0", | 62 | "eslint-config-airbnb-typescript": "^16.1.0", |
63 | "eslint-formatter-gitlab": "^3.0.0", | ||
64 | "eslint-import-resolver-typescript": "^2.5.0", | ||
57 | "eslint-plugin-import": "^2.25.4", | 65 | "eslint-plugin-import": "^2.25.4", |
66 | "eslint-plugin-jsx-a11y": "^6.5.1", | ||
58 | "eslint-plugin-react": "^7.28.0", | 67 | "eslint-plugin-react": "^7.28.0", |
68 | "eslint-plugin-react-hooks": "^4.3.0", | ||
59 | "git-repo-info": "^2.1.1", | 69 | "git-repo-info": "^2.1.1", |
60 | "jest": "^27.4.7", | 70 | "jest": "^27.4.7", |
61 | "rimraf": "^3.0.2", | 71 | "rimraf": "^3.0.2", |
diff --git a/packages/main/.eslintrc.cjs b/packages/main/.eslintrc.cjs new file mode 100644 index 0000000..548ea34 --- /dev/null +++ b/packages/main/.eslintrc.cjs | |||
@@ -0,0 +1,6 @@ | |||
1 | module.exports = { | ||
2 | env: { | ||
3 | node: true, | ||
4 | browser: false, | ||
5 | }, | ||
6 | }; | ||
diff --git a/packages/main/.eslintrc.json b/packages/main/.eslintrc.json deleted file mode 100644 index 6b736e2..0000000 --- a/packages/main/.eslintrc.json +++ /dev/null | |||
@@ -1,6 +0,0 @@ | |||
1 | { | ||
2 | "globals": { | ||
3 | "NodeJS": false, | ||
4 | "require": false | ||
5 | } | ||
6 | } | ||
diff --git a/packages/main/esbuild.config.js b/packages/main/esbuild.config.js index c24d6e1..49fba6b 100644 --- a/packages/main/esbuild.config.js +++ b/packages/main/esbuild.config.js | |||
@@ -1,8 +1,8 @@ | |||
1 | /* eslint-disable no-process-env */ | ||
2 | import getRepoInfo from 'git-repo-info'; | 1 | import getRepoInfo from 'git-repo-info'; |
2 | |||
3 | import { node } from '../../config/buildConstants.js'; | 3 | import { node } from '../../config/buildConstants.js'; |
4 | import { getConfig } from '../../config/esbuildConfig.js'; | 4 | import fileURLToDirname from '../../config/fileURLToDirname.js'; |
5 | import { fileURLToDirname } from '../../config/utils.js'; | 5 | import getEsbuildConfig from '../../config/getEsbuildConfig.js'; |
6 | 6 | ||
7 | const externalPackages = ['electron']; | 7 | const externalPackages = ['electron']; |
8 | 8 | ||
@@ -12,7 +12,7 @@ if (process.env.MODE !== 'development') { | |||
12 | 12 | ||
13 | const gitInfo = getRepoInfo(); | 13 | const gitInfo = getRepoInfo(); |
14 | 14 | ||
15 | export default getConfig({ | 15 | export default getEsbuildConfig({ |
16 | absWorkingDir: fileURLToDirname(import.meta.url), | 16 | absWorkingDir: fileURLToDirname(import.meta.url), |
17 | entryPoints: [ | 17 | entryPoints: [ |
18 | 'src/index.ts', | 18 | 'src/index.ts', |
diff --git a/packages/main/package.json b/packages/main/package.json index e1b3f49..d9abf51 100644 --- a/packages/main/package.json +++ b/packages/main/package.json | |||
@@ -5,7 +5,7 @@ | |||
5 | "type": "module", | 5 | "type": "module", |
6 | "types": "dist-types/index.d.ts", | 6 | "types": "dist-types/index.d.ts", |
7 | "scripts": { | 7 | "scripts": { |
8 | "typecheck": "tsc" | 8 | "typecheck:workspace": "yarn g:typecheck" |
9 | }, | 9 | }, |
10 | "dependencies": { | 10 | "dependencies": { |
11 | "@sophie/service-shared": "workspace:*", | 11 | "@sophie/service-shared": "workspace:*", |
diff --git a/packages/main/src/controllers/__tests__/config.spec.ts b/packages/main/src/controllers/__tests__/initConfig.spec.ts index eb67df0..e386a07 100644 --- a/packages/main/src/controllers/__tests__/config.spec.ts +++ b/packages/main/src/controllers/__tests__/initConfig.spec.ts | |||
@@ -22,20 +22,20 @@ import { jest } from '@jest/globals'; | |||
22 | import { mocked } from 'jest-mock'; | 22 | import { mocked } from 'jest-mock'; |
23 | import ms from 'ms'; | 23 | import ms from 'ms'; |
24 | 24 | ||
25 | import { initConfig } from '../config'; | 25 | import type ConfigPersistenceService from '../../services/ConfigPersistenceService'; |
26 | import type { ConfigPersistenceService } from '../../services/ConfigPersistenceService'; | ||
27 | import { Config, config as configModel } from '../../stores/Config'; | 26 | import { Config, config as configModel } from '../../stores/Config'; |
28 | import { Disposer } from '../../utils/disposer'; | 27 | import type Disposer from '../../utils/Disposer'; |
29 | import { silenceLogger } from '../../utils/logging'; | 28 | import { silenceLogger } from '../../utils/log'; |
29 | import initConfig from '../initConfig'; | ||
30 | 30 | ||
31 | let config: Config; | 31 | let config: Config; |
32 | let persistenceService: ConfigPersistenceService = { | 32 | const persistenceService: ConfigPersistenceService = { |
33 | readConfig: jest.fn(), | 33 | readConfig: jest.fn(), |
34 | writeConfig: jest.fn(), | 34 | writeConfig: jest.fn(), |
35 | watchConfig: jest.fn(), | 35 | watchConfig: jest.fn(), |
36 | }; | 36 | }; |
37 | let lessThanThrottleMs = ms('0.1s'); | 37 | const lessThanThrottleMs = ms('0.1s'); |
38 | let throttleMs = ms('1s'); | 38 | const throttleMs = ms('1s'); |
39 | 39 | ||
40 | beforeAll(() => { | 40 | beforeAll(() => { |
41 | jest.useFakeTimers(); | 41 | jest.useFakeTimers(); |
@@ -108,7 +108,7 @@ describe('when initializing', () => { | |||
108 | 108 | ||
109 | describe('when it has loaded the config', () => { | 109 | describe('when it has loaded the config', () => { |
110 | let sutDisposer: Disposer; | 110 | let sutDisposer: Disposer; |
111 | let watcherDisposer: Disposer = jest.fn(); | 111 | const watcherDisposer: Disposer = jest.fn(); |
112 | let configChangedCallback: () => Promise<void>; | 112 | let configChangedCallback: () => Promise<void>; |
113 | 113 | ||
114 | beforeEach(async () => { | 114 | beforeEach(async () => { |
@@ -118,7 +118,7 @@ describe('when it has loaded the config', () => { | |||
118 | }); | 118 | }); |
119 | mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer); | 119 | mocked(persistenceService.watchConfig).mockReturnValueOnce(watcherDisposer); |
120 | sutDisposer = await initConfig(config, persistenceService, throttleMs); | 120 | sutDisposer = await initConfig(config, persistenceService, throttleMs); |
121 | configChangedCallback = mocked(persistenceService.watchConfig).mock.calls[0][0]; | 121 | [[configChangedCallback]] = mocked(persistenceService.watchConfig).mock.calls; |
122 | jest.resetAllMocks(); | 122 | jest.resetAllMocks(); |
123 | }); | 123 | }); |
124 | 124 | ||
diff --git a/packages/main/src/controllers/__tests__/nativeTheme.spec.ts b/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts index 85d6dd2..bd33f48 100644 --- a/packages/main/src/controllers/__tests__/nativeTheme.spec.ts +++ b/packages/main/src/controllers/__tests__/initNativeTheme.spec.ts | |||
@@ -22,7 +22,7 @@ import { jest } from '@jest/globals'; | |||
22 | import { mocked } from 'jest-mock'; | 22 | import { mocked } from 'jest-mock'; |
23 | 23 | ||
24 | import { createMainStore, MainStore } from '../../stores/MainStore'; | 24 | import { createMainStore, MainStore } from '../../stores/MainStore'; |
25 | import { Disposer } from '../../utils/disposer'; | 25 | import type Disposer from '../../utils/Disposer'; |
26 | 26 | ||
27 | let shouldUseDarkColors = false; | 27 | let shouldUseDarkColors = false; |
28 | 28 | ||
@@ -38,7 +38,7 @@ jest.unstable_mockModule('electron', () => ({ | |||
38 | })); | 38 | })); |
39 | 39 | ||
40 | const { nativeTheme } = await import('electron'); | 40 | const { nativeTheme } = await import('electron'); |
41 | const { initNativeTheme } = await import('../nativeTheme'); | 41 | const { default: initNativeTheme } = await import('../initNativeTheme'); |
42 | 42 | ||
43 | let store: MainStore; | 43 | let store: MainStore; |
44 | let disposeSut: Disposer; | 44 | let disposeSut: Disposer; |
diff --git a/packages/main/src/controllers/config.ts b/packages/main/src/controllers/initConfig.ts index deaeac2..1d40762 100644 --- a/packages/main/src/controllers/config.ts +++ b/packages/main/src/controllers/initConfig.ts | |||
@@ -19,19 +19,19 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { debounce } from 'lodash-es'; | 21 | import { debounce } from 'lodash-es'; |
22 | import ms from 'ms'; | ||
23 | import { applySnapshot, getSnapshot, onSnapshot } from 'mobx-state-tree'; | 22 | import { applySnapshot, getSnapshot, onSnapshot } from 'mobx-state-tree'; |
23 | import ms from 'ms'; | ||
24 | 24 | ||
25 | import type { ConfigPersistenceService } from '../services/ConfigPersistenceService.js'; | 25 | import type ConfigPersistenceService from '../services/ConfigPersistenceService'; |
26 | import type { Config, ConfigSnapshotOut } from '../stores/Config.js'; | 26 | import type { Config, ConfigSnapshotOut } from '../stores/Config'; |
27 | import { Disposer } from '../utils/disposer'; | 27 | import type Disposer from '../utils/Disposer'; |
28 | import { getLogger } from '../utils/logging'; | 28 | import { getLogger } from '../utils/log'; |
29 | 29 | ||
30 | const DEFAULT_CONFIG_DEBOUNCE_TIME = ms('1s'); | 30 | const DEFAULT_CONFIG_DEBOUNCE_TIME = ms('1s'); |
31 | 31 | ||
32 | const log = getLogger('config'); | 32 | const log = getLogger('config'); |
33 | 33 | ||
34 | export async function initConfig( | 34 | export default async function initConfig( |
35 | config: Config, | 35 | config: Config, |
36 | persistenceService: ConfigPersistenceService, | 36 | persistenceService: ConfigPersistenceService, |
37 | debounceTime: number = DEFAULT_CONFIG_DEBOUNCE_TIME, | 37 | debounceTime: number = DEFAULT_CONFIG_DEBOUNCE_TIME, |
diff --git a/packages/main/src/controllers/nativeTheme.ts b/packages/main/src/controllers/initNativeTheme.ts index ccd12d8..d2074ab 100644 --- a/packages/main/src/controllers/nativeTheme.ts +++ b/packages/main/src/controllers/initNativeTheme.ts | |||
@@ -21,13 +21,13 @@ | |||
21 | import { nativeTheme } from 'electron'; | 21 | import { nativeTheme } from 'electron'; |
22 | import { autorun } from 'mobx'; | 22 | import { autorun } from 'mobx'; |
23 | 23 | ||
24 | import type { MainStore } from '../stores/MainStore.js'; | 24 | import type { MainStore } from '../stores/MainStore'; |
25 | import { Disposer } from '../utils/disposer'; | 25 | import type Disposer from '../utils/Disposer'; |
26 | import { getLogger } from '../utils/logging'; | 26 | import { getLogger } from '../utils/log'; |
27 | 27 | ||
28 | const log = getLogger('nativeTheme'); | 28 | const log = getLogger('nativeTheme'); |
29 | 29 | ||
30 | export function initNativeTheme(store: MainStore): Disposer { | 30 | export default function initNativeTheme(store: MainStore): Disposer { |
31 | log.trace('Initializing nativeTheme controller'); | 31 | log.trace('Initializing nativeTheme controller'); |
32 | 32 | ||
33 | const disposeThemeSourceReaction = autorun(() => { | 33 | const disposeThemeSourceReaction = autorun(() => { |
diff --git a/packages/main/src/devTools.ts b/packages/main/src/devTools.ts index 398904c..0486c36 100644 --- a/packages/main/src/devTools.ts +++ b/packages/main/src/devTools.ts | |||
@@ -46,7 +46,12 @@ export async function installDevToolsExtensions(): Promise<void> { | |||
46 | default: installExtension, | 46 | default: installExtension, |
47 | REACT_DEVELOPER_TOOLS, | 47 | REACT_DEVELOPER_TOOLS, |
48 | REDUX_DEVTOOLS, | 48 | REDUX_DEVTOOLS, |
49 | } = require('electron-devtools-installer'); | 49 | /* eslint-disable-next-line |
50 | import/no-extraneous-dependencies, | ||
51 | global-require, | ||
52 | @typescript-eslint/no-var-requires | ||
53 | */ | ||
54 | } = require('electron-devtools-installer') as typeof import('electron-devtools-installer'); | ||
50 | await installExtension( | 55 | await installExtension( |
51 | [ | 56 | [ |
52 | REACT_DEVELOPER_TOOLS, | 57 | REACT_DEVELOPER_TOOLS, |
diff --git a/packages/main/src/index.ts b/packages/main/src/index.ts index d0191b7..bc10b4c 100644 --- a/packages/main/src/index.ts +++ b/packages/main/src/index.ts | |||
@@ -19,18 +19,10 @@ | |||
19 | * SPDX-License-Identifier: AGPL-3.0-only | 19 | * SPDX-License-Identifier: AGPL-3.0-only |
20 | */ | 20 | */ |
21 | 21 | ||
22 | import { | ||
23 | app, | ||
24 | BrowserView, | ||
25 | BrowserWindow, | ||
26 | ipcMain, | ||
27 | } from 'electron'; | ||
28 | import { arch } from 'os'; | 22 | import { arch } from 'os'; |
29 | import osName from 'os-name'; | ||
30 | import { ensureDirSync, readFile, readFileSync } from 'fs-extra'; | ||
31 | import { autorun } from 'mobx'; | ||
32 | import { getSnapshot, onPatch } from 'mobx-state-tree'; | ||
33 | import { join } from 'path'; | 23 | import { join } from 'path'; |
24 | import { URL } from 'url'; | ||
25 | |||
34 | import { | 26 | import { |
35 | ServiceToMainIpcMessage, | 27 | ServiceToMainIpcMessage, |
36 | unreadCount, | 28 | unreadCount, |
@@ -41,18 +33,30 @@ import { | |||
41 | MainToRendererIpcMessage, | 33 | MainToRendererIpcMessage, |
42 | RendererToMainIpcMessage, | 34 | RendererToMainIpcMessage, |
43 | } from '@sophie/shared'; | 35 | } from '@sophie/shared'; |
44 | import { URL } from 'url'; | 36 | import { |
37 | app, | ||
38 | BrowserView, | ||
39 | BrowserWindow, | ||
40 | ipcMain, | ||
41 | } from 'electron'; | ||
42 | import { ensureDirSync, readFile, readFileSync } from 'fs-extra'; | ||
43 | import { autorun } from 'mobx'; | ||
44 | import { getSnapshot, onPatch } from 'mobx-state-tree'; | ||
45 | import osName from 'os-name'; | ||
45 | 46 | ||
46 | import { init } from './compositionRoot'; | ||
47 | import { | 47 | import { |
48 | DEVMODE_ALLOWED_URL_PREFIXES, | 48 | DEVMODE_ALLOWED_URL_PREFIXES, |
49 | installDevToolsExtensions, | 49 | installDevToolsExtensions, |
50 | openDevToolsWhenReady, | 50 | openDevToolsWhenReady, |
51 | } from './devTools'; | 51 | } from './devTools'; |
52 | import init from './init'; | ||
52 | import { createMainStore } from './stores/MainStore'; | 53 | import { createMainStore } from './stores/MainStore'; |
54 | import { getLogger } from './utils/log'; | ||
53 | 55 | ||
54 | const isDevelopment = import.meta.env.MODE === 'development'; | 56 | const isDevelopment = import.meta.env.MODE === 'development'; |
55 | 57 | ||
58 | const log = getLogger('index'); | ||
59 | |||
56 | // Always enable sandboxing. | 60 | // Always enable sandboxing. |
57 | app.enableSandbox(); | 61 | app.enableSandbox(); |
58 | 62 | ||
@@ -93,7 +97,7 @@ app.setAboutPanelOptions({ | |||
93 | `Node.js: ${process.versions.node}`, | 97 | `Node.js: ${process.versions.node}`, |
94 | `Platform: ${osName()}`, | 98 | `Platform: ${osName()}`, |
95 | `Arch: ${arch()}`, | 99 | `Arch: ${arch()}`, |
96 | `Build date: ${new Date(Number(import.meta.env.BUILD_DATE))}`, | 100 | `Build date: ${new Date(Number(import.meta.env.BUILD_DATE)).toLocaleString()}`, |
97 | `Git SHA: ${import.meta.env.GIT_SHA}`, | 101 | `Git SHA: ${import.meta.env.GIT_SHA}`, |
98 | `Git branch: ${import.meta.env.GIT_BRANCH}`, | 102 | `Git branch: ${import.meta.env.GIT_BRANCH}`, |
99 | ].join('\n'), | 103 | ].join('\n'), |
@@ -109,9 +113,9 @@ function getResourceUrl(relativePath: string): string { | |||
109 | return new URL(relativePath, baseUrl).toString(); | 113 | return new URL(relativePath, baseUrl).toString(); |
110 | } | 114 | } |
111 | 115 | ||
112 | let serviceInjectRelativePath = '../../service-inject/dist/index.js'; | 116 | const serviceInjectRelativePath = '../../service-inject/dist/index.js'; |
113 | let serviceInjectPath = getResourcePath(serviceInjectRelativePath); | 117 | const serviceInjectPath = getResourcePath(serviceInjectRelativePath); |
114 | let serviceInject: WebSource = { | 118 | const serviceInject: WebSource = { |
115 | code: readFileSync(serviceInjectPath, 'utf8'), | 119 | code: readFileSync(serviceInjectPath, 'utf8'), |
116 | url: getResourceUrl(serviceInjectRelativePath), | 120 | url: getResourceUrl(serviceInjectRelativePath), |
117 | }; | 121 | }; |
@@ -122,7 +126,7 @@ const store = createMainStore(); | |||
122 | init(store).then((disposeCompositionRoot) => { | 126 | init(store).then((disposeCompositionRoot) => { |
123 | app.on('will-quit', disposeCompositionRoot); | 127 | app.on('will-quit', disposeCompositionRoot); |
124 | }).catch((err) => { | 128 | }).catch((err) => { |
125 | console.log('Failed to initialize application', err); | 129 | log.log('Failed to initialize application', err); |
126 | }); | 130 | }); |
127 | 131 | ||
128 | const rendererBaseUrl = getResourceUrl('../renderer/'); | 132 | const rendererBaseUrl = getResourceUrl('../renderer/'); |
@@ -211,7 +215,7 @@ async function createWindow(): Promise<unknown> { | |||
211 | 215 | ||
212 | ipcMain.handle(RendererToMainIpcMessage.GetSharedStoreSnapshot, (event) => { | 216 | ipcMain.handle(RendererToMainIpcMessage.GetSharedStoreSnapshot, (event) => { |
213 | if (event.sender.id !== webContents.id) { | 217 | if (event.sender.id !== webContents.id) { |
214 | console.warn( | 218 | log.warn( |
215 | 'Unexpected', | 219 | 'Unexpected', |
216 | RendererToMainIpcMessage.GetSharedStoreSnapshot, | 220 | RendererToMainIpcMessage.GetSharedStoreSnapshot, |
217 | 'from webContents', | 221 | 'from webContents', |
@@ -224,7 +228,7 @@ async function createWindow(): Promise<unknown> { | |||
224 | 228 | ||
225 | ipcMain.on(RendererToMainIpcMessage.DispatchAction, (event, rawAction) => { | 229 | ipcMain.on(RendererToMainIpcMessage.DispatchAction, (event, rawAction) => { |
226 | if (event.sender.id !== webContents.id) { | 230 | if (event.sender.id !== webContents.id) { |
227 | console.warn( | 231 | log.warn( |
228 | 'Unexpected', | 232 | 'Unexpected', |
229 | RendererToMainIpcMessage.DispatchAction, | 233 | RendererToMainIpcMessage.DispatchAction, |
230 | 'from webContents', | 234 | 'from webContents', |
@@ -242,17 +246,26 @@ async function createWindow(): Promise<unknown> { | |||
242 | store.config.setThemeSource(actionToDispatch.themeSource); | 246 | store.config.setThemeSource(actionToDispatch.themeSource); |
243 | break; | 247 | break; |
244 | case 'reload-all-services': | 248 | case 'reload-all-services': |
245 | readFile(serviceInjectPath, 'utf8').then((data) => { | 249 | readFile(serviceInjectPath, 'utf8') |
246 | serviceInject.code = data; | 250 | .then((data) => { |
247 | }).catch((err) => { | 251 | serviceInject.code = data; |
248 | console.error('Error while reloading', serviceInjectPath, err); | 252 | }) |
249 | }).then(() => { | 253 | .catch((err) => { |
250 | browserView.webContents.reload(); | 254 | log.error('Error while reloading', serviceInjectPath, err); |
251 | }); | 255 | }) |
256 | .then(() => { | ||
257 | browserView.webContents.reload(); | ||
258 | }) | ||
259 | .catch((err) => { | ||
260 | log.error('Failed to reload browserView', err); | ||
261 | }); | ||
262 | break; | ||
263 | default: | ||
264 | log.error('Unexpected action from UI renderer:', actionToDispatch); | ||
252 | break; | 265 | break; |
253 | } | 266 | } |
254 | } catch (err) { | 267 | } catch (err) { |
255 | console.error('Error while dispatching renderer action', rawAction, err); | 268 | log.error('Error while dispatching renderer action', rawAction, err); |
256 | } | 269 | } |
257 | }); | 270 | }); |
258 | 271 | ||
@@ -260,11 +273,10 @@ async function createWindow(): Promise<unknown> { | |||
260 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); | 273 | webContents.send(MainToRendererIpcMessage.SharedStorePatch, patch); |
261 | }); | 274 | }); |
262 | 275 | ||
263 | ipcMain.handle(ServiceToMainIpcMessage.ApiExposedInMainWorld, (event) => { | 276 | ipcMain.handle( |
264 | return event.sender.id === browserView.webContents.id | 277 | ServiceToMainIpcMessage.ApiExposedInMainWorld, |
265 | ? serviceInject | 278 | (event) => (event.sender.id === browserView.webContents.id ? serviceInject : null), |
266 | : null; | 279 | ); |
267 | }); | ||
268 | 280 | ||
269 | browserView.webContents.on('ipc-message', (_event, channel, ...args) => { | 281 | browserView.webContents.on('ipc-message', (_event, channel, ...args) => { |
270 | try { | 282 | try { |
@@ -274,14 +286,14 @@ async function createWindow(): Promise<unknown> { | |||
274 | // otherwise electron emits a no handler registered warning. | 286 | // otherwise electron emits a no handler registered warning. |
275 | break; | 287 | break; |
276 | case ServiceToMainIpcMessage.SetUnreadCount: | 288 | case ServiceToMainIpcMessage.SetUnreadCount: |
277 | console.log('Unread count:', unreadCount.parse(args[0])); | 289 | log.log('Unread count:', unreadCount.parse(args[0])); |
278 | break; | 290 | break; |
279 | default: | 291 | default: |
280 | console.error('Unknown IPC message:', channel, args); | 292 | log.error('Unknown IPC message:', channel, args); |
281 | break; | 293 | break; |
282 | } | 294 | } |
283 | } catch (err) { | 295 | } catch (err) { |
284 | console.error('Error while processing IPC message:', channel, args, err); | 296 | log.error('Error while processing IPC message:', channel, args, err); |
285 | } | 297 | } |
286 | }); | 298 | }); |
287 | 299 | ||
@@ -291,17 +303,22 @@ async function createWindow(): Promise<unknown> { | |||
291 | }, | 303 | }, |
292 | ); | 304 | ); |
293 | 305 | ||
294 | browserView.webContents.session.webRequest.onBeforeSendHeaders(({ url, requestHeaders }, callback) => { | 306 | browserView.webContents.session.webRequest.onBeforeSendHeaders( |
295 | if (url.match(/^[^:]+:\/\/accounts\.google\.[^.\/]+\//)) { | 307 | ({ url, requestHeaders }, callback) => { |
296 | requestHeaders['User-Agent'] = chromelessUserAgent; | 308 | const requestUserAgent = url.match(/^[^:]+:\/\/accounts\.google\.[^./]+\//) |
297 | } else { | 309 | ? chromelessUserAgent |
298 | requestHeaders['User-Agent'] = userAgent; | 310 | : userAgent; |
299 | } | 311 | callback({ |
300 | callback({ requestHeaders }); | 312 | requestHeaders: { |
301 | }); | 313 | ...requestHeaders, |
314 | 'User-Agent': requestUserAgent, | ||
315 | }, | ||
316 | }); | ||
317 | }, | ||
318 | ); | ||
302 | 319 | ||
303 | browserView.webContents.loadURL('https://gitlab.com/say-hi-to-sophie/sophie').catch((err) => { | 320 | browserView.webContents.loadURL('https://gitlab.com/say-hi-to-sophie/sophie').catch((err) => { |
304 | console.error('Failed to load browser', err); | 321 | log.error('Failed to load browser', err); |
305 | }); | 322 | }); |
306 | 323 | ||
307 | return mainWindow.loadURL(pageUrl); | 324 | return mainWindow.loadURL(pageUrl); |
@@ -330,12 +347,12 @@ app.whenReady().then(async () => { | |||
330 | try { | 347 | try { |
331 | await installDevToolsExtensions(); | 348 | await installDevToolsExtensions(); |
332 | } catch (err) { | 349 | } catch (err) { |
333 | console.error('Failed to install devtools extensions', err); | 350 | log.error('Failed to install devtools extensions', err); |
334 | } | 351 | } |
335 | } | 352 | } |
336 | 353 | ||
337 | return createWindow(); | 354 | return createWindow(); |
338 | }).catch((err) => { | 355 | }).catch((err) => { |
339 | console.error('Failed to create window', err); | 356 | log.error('Failed to create window', err); |
340 | process.exit(1); | 357 | process.exit(1); |
341 | }); | 358 | }); |
diff --git a/packages/main/src/compositionRoot.ts b/packages/main/src/init.ts index 76835a1..4487cc4 100644 --- a/packages/main/src/compositionRoot.ts +++ b/packages/main/src/init.ts | |||
@@ -20,13 +20,13 @@ | |||
20 | 20 | ||
21 | import { app } from 'electron'; | 21 | import { app } from 'electron'; |
22 | 22 | ||
23 | import { initConfig } from './controllers/config'; | 23 | import initConfig from './controllers/initConfig'; |
24 | import { initNativeTheme } from './controllers/nativeTheme'; | 24 | import initNativeTheme from './controllers/initNativeTheme'; |
25 | import { ConfigPersistenceServiceImpl } from './services/impl/ConfigPersistenceServiceImpl'; | 25 | import ConfigPersistenceServiceImpl from './services/impl/ConfigPersistenceServiceImpl'; |
26 | import { MainStore } from './stores/MainStore'; | 26 | import { MainStore } from './stores/MainStore'; |
27 | import { Disposer } from './utils/disposer'; | 27 | import type Disposer from './utils/Disposer'; |
28 | 28 | ||
29 | export async function init(store: MainStore): Promise<Disposer> { | 29 | export default async function init(store: MainStore): Promise<Disposer> { |
30 | const configPersistenceService = new ConfigPersistenceServiceImpl(app.getPath('userData')); | 30 | const configPersistenceService = new ConfigPersistenceServiceImpl(app.getPath('userData')); |
31 | const disposeConfigController = await initConfig(store.config, configPersistenceService); | 31 | const disposeConfigController = await initConfig(store.config, configPersistenceService); |
32 | const disposeNativeThemeController = initNativeTheme(store); | 32 | const disposeNativeThemeController = initNativeTheme(store); |
diff --git a/packages/main/src/services/ConfigPersistenceService.ts b/packages/main/src/services/ConfigPersistenceService.ts index aed0ba3..7d508c5 100644 --- a/packages/main/src/services/ConfigPersistenceService.ts +++ b/packages/main/src/services/ConfigPersistenceService.ts | |||
@@ -18,12 +18,12 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import type { ConfigSnapshotOut } from '../stores/Config'; | 21 | import type { ConfigSnapshotOut } from '../stores/Config'; |
22 | import { Disposer } from '../utils/disposer'; | 22 | import type Disposer from '../utils/Disposer'; |
23 | 23 | ||
24 | export type ReadConfigResult = { found: true; data: unknown; } | { found: false; }; | 24 | export type ReadConfigResult = { found: true; data: unknown; } | { found: false; }; |
25 | 25 | ||
26 | export interface ConfigPersistenceService { | 26 | export default interface ConfigPersistenceService { |
27 | readConfig(): Promise<ReadConfigResult>; | 27 | readConfig(): Promise<ReadConfigResult>; |
28 | 28 | ||
29 | writeConfig(configSnapshot: ConfigSnapshotOut): Promise<void>; | 29 | writeConfig(configSnapshot: ConfigSnapshotOut): Promise<void>; |
diff --git a/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts b/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts index 2d19632..df8c807 100644 --- a/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts +++ b/packages/main/src/services/impl/ConfigPersistenceServiceImpl.ts | |||
@@ -19,18 +19,20 @@ | |||
19 | */ | 19 | */ |
20 | import { watch } from 'fs'; | 20 | import { watch } from 'fs'; |
21 | import { readFile, stat, writeFile } from 'fs/promises'; | 21 | import { readFile, stat, writeFile } from 'fs/promises'; |
22 | import JSON5 from 'json5'; | ||
23 | import { throttle } from 'lodash-es'; | ||
24 | import { join } from 'path'; | 22 | import { join } from 'path'; |
25 | 23 | ||
26 | import type { ConfigPersistenceService, ReadConfigResult } from '../ConfigPersistenceService.js'; | 24 | import JSON5 from 'json5'; |
27 | import type { ConfigSnapshotOut } from '../../stores/Config.js'; | 25 | import throttle from 'lodash-es/throttle'; |
28 | import { Disposer } from '../../utils/disposer'; | 26 | |
29 | import { getLogger } from '../../utils/logging'; | 27 | import type { ConfigSnapshotOut } from '../../stores/Config'; |
28 | import type Disposer from '../../utils/Disposer'; | ||
29 | import { getLogger } from '../../utils/log'; | ||
30 | import type ConfigPersistenceService from '../ConfigPersistenceService'; | ||
31 | import type { ReadConfigResult } from '../ConfigPersistenceService'; | ||
30 | 32 | ||
31 | const log = getLogger('configPersistence'); | 33 | const log = getLogger('configPersistence'); |
32 | 34 | ||
33 | export class ConfigPersistenceServiceImpl implements ConfigPersistenceService { | 35 | export default class ConfigPersistenceServiceImpl implements ConfigPersistenceService { |
34 | private readonly configFilePath: string; | 36 | private readonly configFilePath: string; |
35 | 37 | ||
36 | private writingConfig = false; | 38 | private writingConfig = false; |
@@ -103,7 +105,7 @@ export class ConfigPersistenceServiceImpl implements ConfigPersistenceService { | |||
103 | 'whish is newer than last written', | 105 | 'whish is newer than last written', |
104 | this.timeLastWritten, | 106 | this.timeLastWritten, |
105 | ); | 107 | ); |
106 | return callback(); | 108 | await callback(); |
107 | } | 109 | } |
108 | }, throttleMs); | 110 | }, throttleMs); |
109 | 111 | ||
@@ -115,7 +117,7 @@ export class ConfigPersistenceServiceImpl implements ConfigPersistenceService { | |||
115 | if (eventType === 'change' | 117 | if (eventType === 'change' |
116 | && (filename === this.configFileName || filename === null)) { | 118 | && (filename === this.configFileName || filename === null)) { |
117 | configChanged()?.catch((err) => { | 119 | configChanged()?.catch((err) => { |
118 | console.log('Unhandled error while listening for config changes', err); | 120 | log.error('Unhandled error while listening for config changes', err); |
119 | }); | 121 | }); |
120 | } | 122 | } |
121 | }); | 123 | }); |
diff --git a/packages/main/src/stores/Config.ts b/packages/main/src/stores/Config.ts index 7d1168f..06dbdeb 100644 --- a/packages/main/src/stores/Config.ts +++ b/packages/main/src/stores/Config.ts | |||
@@ -18,13 +18,13 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { Instance } from 'mobx-state-tree'; | ||
22 | import { | 21 | import { |
23 | config as originalConfig, | 22 | config as originalConfig, |
24 | ConfigSnapshotIn, | 23 | ConfigSnapshotIn, |
25 | ConfigSnapshotOut, | 24 | ConfigSnapshotOut, |
26 | ThemeSource, | 25 | ThemeSource, |
27 | } from '@sophie/shared'; | 26 | } from '@sophie/shared'; |
27 | import { Instance } from 'mobx-state-tree'; | ||
28 | 28 | ||
29 | export const config = originalConfig.actions((self) => ({ | 29 | export const config = originalConfig.actions((self) => ({ |
30 | setThemeSource(mode: ThemeSource) { | 30 | setThemeSource(mode: ThemeSource) { |
diff --git a/packages/main/src/stores/MainStore.ts b/packages/main/src/stores/MainStore.ts index f8a09d6..7b26c52 100644 --- a/packages/main/src/stores/MainStore.ts +++ b/packages/main/src/stores/MainStore.ts | |||
@@ -18,8 +18,8 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { applySnapshot, Instance, types } from 'mobx-state-tree'; | ||
22 | import { BrowserViewBounds } from '@sophie/shared'; | 21 | import { BrowserViewBounds } from '@sophie/shared'; |
22 | import { applySnapshot, Instance, types } from 'mobx-state-tree'; | ||
23 | 23 | ||
24 | import type { Config } from './Config.js'; | 24 | import type { Config } from './Config.js'; |
25 | import { sharedStore } from './SharedStore'; | 25 | import { sharedStore } from './SharedStore'; |
diff --git a/packages/main/src/stores/SharedStore.ts b/packages/main/src/stores/SharedStore.ts index e20150d..c023fc7 100644 --- a/packages/main/src/stores/SharedStore.ts +++ b/packages/main/src/stores/SharedStore.ts | |||
@@ -18,8 +18,8 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { Instance, types } from 'mobx-state-tree'; | ||
22 | import { sharedStore as originalSharedStore } from '@sophie/shared'; | 21 | import { sharedStore as originalSharedStore } from '@sophie/shared'; |
22 | import { Instance, types } from 'mobx-state-tree'; | ||
23 | 23 | ||
24 | import { config } from './Config'; | 24 | import { config } from './Config'; |
25 | 25 | ||
diff --git a/packages/main/src/utils/disposer.ts b/packages/main/src/utils/Disposer.ts index 0d469dd..2e0ca25 100644 --- a/packages/main/src/utils/disposer.ts +++ b/packages/main/src/utils/Disposer.ts | |||
@@ -20,4 +20,6 @@ | |||
20 | 20 | ||
21 | import { IDisposer } from 'mobx-state-tree'; | 21 | import { IDisposer } from 'mobx-state-tree'; |
22 | 22 | ||
23 | export type Disposer = IDisposer; | 23 | type Disposer = IDisposer; |
24 | |||
25 | export default Disposer; | ||
diff --git a/packages/main/src/utils/logging.ts b/packages/main/src/utils/log.ts index f703749..c704797 100644 --- a/packages/main/src/utils/logging.ts +++ b/packages/main/src/utils/log.ts | |||
@@ -45,7 +45,11 @@ prefix.reg(loglevel); | |||
45 | prefix.apply(loglevel, { | 45 | prefix.apply(loglevel, { |
46 | format(level, name, timestamp) { | 46 | format(level, name, timestamp) { |
47 | const levelColor = getColor(level); | 47 | const levelColor = getColor(level); |
48 | return `${chalk.gray(`[${timestamp}]`)} ${levelColor(level)} ${chalk.green(`${name}:`)}`; | 48 | const timeStr = timestamp.toString(); |
49 | const nameStr = typeof name === 'undefined' | ||
50 | ? levelColor(':') | ||
51 | : ` ${chalk.green(`${name}:`)}`; | ||
52 | return `${chalk.gray(`[${timeStr}]`)} ${levelColor(level)}${nameStr}`; | ||
49 | }, | 53 | }, |
50 | }); | 54 | }); |
51 | 55 | ||
@@ -56,7 +60,7 @@ export function getLogger(loggerName: string): Logger { | |||
56 | export function silenceLogger(): void { | 60 | export function silenceLogger(): void { |
57 | loglevel.disableAll(); | 61 | loglevel.disableAll(); |
58 | const loggers = loglevel.getLoggers(); | 62 | const loggers = loglevel.getLoggers(); |
59 | for (const loggerName of Object.keys(loggers)) { | 63 | Object.keys(loggers).forEach((loggerName) => { |
60 | loggers[loggerName].disableAll(); | 64 | loggers[loggerName].disableAll(); |
61 | } | 65 | }); |
62 | } | 66 | } |
diff --git a/packages/main/tsconfig.json b/packages/main/tsconfig.json index 1401445..00a1985 100644 --- a/packages/main/tsconfig.json +++ b/packages/main/tsconfig.json | |||
@@ -1,5 +1,5 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "../../config/tsconfig.base.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "noEmit": true, | 4 | "noEmit": true, |
5 | "types": [ | 5 | "types": [ |
@@ -9,14 +9,16 @@ | |||
9 | }, | 9 | }, |
10 | "references": [ | 10 | "references": [ |
11 | { | 11 | { |
12 | "path": "../service-shared" | 12 | "path": "../service-shared/tsconfig.build.json" |
13 | }, | 13 | }, |
14 | { | 14 | { |
15 | "path": "../shared" | 15 | "path": "../shared/tsconfig.build.json" |
16 | } | 16 | } |
17 | ], | 17 | ], |
18 | "include": [ | 18 | "include": [ |
19 | "src/**/*.ts", | 19 | "src/**/*.ts", |
20 | "types/**/*.d.ts" | 20 | "types/**/*.d.ts", |
21 | "esbuild.config.js", | ||
22 | "jest.config.js" | ||
21 | ] | 23 | ] |
22 | } | 24 | } |
diff --git a/packages/preload/.eslintrc.cjs b/packages/preload/.eslintrc.cjs new file mode 100644 index 0000000..02fab21 --- /dev/null +++ b/packages/preload/.eslintrc.cjs | |||
@@ -0,0 +1,6 @@ | |||
1 | module.exports = { | ||
2 | env: { | ||
3 | node: true, | ||
4 | browser: true, | ||
5 | }, | ||
6 | }; | ||
diff --git a/packages/preload/esbuild.config.js b/packages/preload/esbuild.config.js index b73a071..66f5e84 100644 --- a/packages/preload/esbuild.config.js +++ b/packages/preload/esbuild.config.js | |||
@@ -1,8 +1,8 @@ | |||
1 | import { chrome } from '../../config/buildConstants.js'; | 1 | import { chrome } from '../../config/buildConstants.js'; |
2 | import { getConfig } from '../../config/esbuildConfig.js'; | 2 | import fileURLToDirname from '../../config/fileURLToDirname.js'; |
3 | import { fileURLToDirname } from '../../config/utils.js'; | 3 | import getEsbuildConfig from '../../config/getEsbuildConfig.js'; |
4 | 4 | ||
5 | export default getConfig({ | 5 | export default getEsbuildConfig({ |
6 | absWorkingDir: fileURLToDirname(import.meta.url), | 6 | absWorkingDir: fileURLToDirname(import.meta.url), |
7 | entryPoints: [ | 7 | entryPoints: [ |
8 | 'src/index.ts', | 8 | 'src/index.ts', |
diff --git a/packages/preload/jest.config.js b/packages/preload/jest.config.js index e474c4c..27af475 100644 --- a/packages/preload/jest.config.js +++ b/packages/preload/jest.config.js | |||
@@ -1,6 +1,6 @@ | |||
1 | import rootConfig from '../../config/jest.config.base.js'; | 1 | import rootConfig from '../../config/jest.config.base.js'; |
2 | 2 | ||
3 | /** @type {import('ts-jest').InitialOptionsTsJest} */ | 3 | /** @type {import('@jest/types').Config.InitialOptions} */ |
4 | export default { | 4 | export default { |
5 | ...rootConfig, | 5 | ...rootConfig, |
6 | testEnvironment: 'jsdom', | 6 | testEnvironment: 'jsdom', |
diff --git a/packages/preload/package.json b/packages/preload/package.json index 0957aaf..a03d7d9 100644 --- a/packages/preload/package.json +++ b/packages/preload/package.json | |||
@@ -6,7 +6,7 @@ | |||
6 | "type": "module", | 6 | "type": "module", |
7 | "types": "dist-types/index.d.ts", | 7 | "types": "dist-types/index.d.ts", |
8 | "scripts": { | 8 | "scripts": { |
9 | "typecheck": "tsc" | 9 | "typecheck:workspace": "yarn g:typecheck" |
10 | }, | 10 | }, |
11 | "dependencies": { | 11 | "dependencies": { |
12 | "@sophie/shared": "workspace:*", | 12 | "@sophie/shared": "workspace:*", |
@@ -20,8 +20,6 @@ | |||
20 | "@types/jest": "^27.4.0", | 20 | "@types/jest": "^27.4.0", |
21 | "jest": "^27.4.7", | 21 | "jest": "^27.4.7", |
22 | "jest-mock": "^27.4.6", | 22 | "jest-mock": "^27.4.6", |
23 | "jsdom": "^19.0.0", | 23 | "jsdom": "^19.0.0" |
24 | "rimraf": "^3.0.2", | ||
25 | "typescript": "^4.5.4" | ||
26 | } | 24 | } |
27 | } | 25 | } |
diff --git a/packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts index ff77a63..a38dbac 100644 --- a/packages/preload/src/contextBridge/__tests__/SophieRendererImpl.spec.ts +++ b/packages/preload/src/contextBridge/__tests__/createSophieRenderer.spec.ts | |||
@@ -19,9 +19,6 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { jest } from '@jest/globals'; | 21 | import { jest } from '@jest/globals'; |
22 | import { mocked } from 'jest-mock'; | ||
23 | import log from 'loglevel'; | ||
24 | import type { IJsonPatch } from 'mobx-state-tree'; | ||
25 | import { | 22 | import { |
26 | Action, | 23 | Action, |
27 | MainToRendererIpcMessage, | 24 | MainToRendererIpcMessage, |
@@ -29,6 +26,9 @@ import { | |||
29 | SharedStoreSnapshotIn, | 26 | SharedStoreSnapshotIn, |
30 | SophieRenderer, | 27 | SophieRenderer, |
31 | } from '@sophie/shared'; | 28 | } from '@sophie/shared'; |
29 | import { mocked } from 'jest-mock'; | ||
30 | import log from 'loglevel'; | ||
31 | import type { IJsonPatch } from 'mobx-state-tree'; | ||
32 | 32 | ||
33 | jest.unstable_mockModule('electron', () => ({ | 33 | jest.unstable_mockModule('electron', () => ({ |
34 | ipcRenderer: { | 34 | ipcRenderer: { |
@@ -40,7 +40,7 @@ jest.unstable_mockModule('electron', () => ({ | |||
40 | 40 | ||
41 | const { ipcRenderer } = await import('electron'); | 41 | const { ipcRenderer } = await import('electron'); |
42 | 42 | ||
43 | const { createSophieRenderer } = await import('../SophieRendererImpl'); | 43 | const { default: createSophieRenderer } = await import('../createSophieRenderer'); |
44 | 44 | ||
45 | const event: Electron.IpcRendererEvent = null as unknown as Electron.IpcRendererEvent; | 45 | const event: Electron.IpcRendererEvent = null as unknown as Electron.IpcRendererEvent; |
46 | 46 | ||
@@ -81,10 +81,10 @@ describe('createSophieRenderer', () => { | |||
81 | }); | 81 | }); |
82 | }); | 82 | }); |
83 | 83 | ||
84 | describe('SophieRendererImpl', () => { | 84 | describe('SharedStoreConnector', () => { |
85 | let sut: SophieRenderer; | 85 | let sut: SophieRenderer; |
86 | let onSharedStorePatch: (event1: Electron.IpcRendererEvent, patch1: unknown) => void; | 86 | let onSharedStorePatch: (eventArg: Electron.IpcRendererEvent, patchArg: unknown) => void; |
87 | let listener = { | 87 | const listener = { |
88 | // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars | 88 | // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars |
89 | onSnapshot: jest.fn((_snapshot: SharedStoreSnapshotIn) => {}), | 89 | onSnapshot: jest.fn((_snapshot: SharedStoreSnapshotIn) => {}), |
90 | // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars | 90 | // eslint-disable-next-line @typescript-eslint/no-unused-vars, no-unused-vars |
@@ -93,9 +93,9 @@ describe('SophieRendererImpl', () => { | |||
93 | 93 | ||
94 | beforeEach(() => { | 94 | beforeEach(() => { |
95 | sut = createSophieRenderer(false); | 95 | sut = createSophieRenderer(false); |
96 | onSharedStorePatch = mocked(ipcRenderer.on).mock.calls.find(([channel]) => { | 96 | [, onSharedStorePatch] = mocked(ipcRenderer.on).mock.calls.find( |
97 | return channel === MainToRendererIpcMessage.SharedStorePatch; | 97 | ([channel]) => channel === MainToRendererIpcMessage.SharedStorePatch, |
98 | })?.[1]!; | 98 | )!; |
99 | }); | 99 | }); |
100 | 100 | ||
101 | describe('onSharedStoreChange', () => { | 101 | describe('onSharedStoreChange', () => { |
@@ -140,15 +140,15 @@ describe('SophieRendererImpl', () => { | |||
140 | }); | 140 | }); |
141 | }); | 141 | }); |
142 | 142 | ||
143 | function itRefusesToRegisterAnotherListener() { | 143 | function itRefusesToRegisterAnotherListener(): void { |
144 | it('should refuse to register another listener', async () => { | 144 | it('should refuse to register another listener', async () => { |
145 | await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf(Error); | 145 | await expect(sut.onSharedStoreChange(listener)).rejects.toBeInstanceOf(Error); |
146 | }); | 146 | }); |
147 | } | 147 | } |
148 | 148 | ||
149 | function itDoesNotPassPatchesToTheListener( | 149 | function itDoesNotPassPatchesToTheListener( |
150 | name: string = 'should not pass patches to the listener', | 150 | name = 'should not pass patches to the listener', |
151 | ) { | 151 | ): void { |
152 | it(name, () => { | 152 | it(name, () => { |
153 | onSharedStorePatch(event, patch); | 153 | onSharedStorePatch(event, patch); |
154 | expect(listener.onPatch).not.toBeCalled(); | 154 | expect(listener.onPatch).not.toBeCalled(); |
diff --git a/packages/preload/src/contextBridge/SophieRendererImpl.ts b/packages/preload/src/contextBridge/createSophieRenderer.ts index f3c07c5..2055080 100644 --- a/packages/preload/src/contextBridge/SophieRendererImpl.ts +++ b/packages/preload/src/contextBridge/createSophieRenderer.ts | |||
@@ -18,9 +18,6 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { ipcRenderer } from 'electron'; | ||
22 | import log from 'loglevel'; | ||
23 | import type { IJsonPatch } from 'mobx-state-tree'; | ||
24 | import { | 21 | import { |
25 | Action, | 22 | Action, |
26 | action, | 23 | action, |
@@ -30,9 +27,12 @@ import { | |||
30 | SharedStoreListener, | 27 | SharedStoreListener, |
31 | SophieRenderer, | 28 | SophieRenderer, |
32 | } from '@sophie/shared'; | 29 | } from '@sophie/shared'; |
30 | import { ipcRenderer } from 'electron'; | ||
31 | import log from 'loglevel'; | ||
32 | import type { IJsonPatch } from 'mobx-state-tree'; | ||
33 | 33 | ||
34 | class SophieRendererImpl implements SophieRenderer { | 34 | class SharedStoreConnector { |
35 | private onSharedStoreChangeCalled: boolean = false; | 35 | private onSharedStoreChangeCalled = false; |
36 | 36 | ||
37 | private listener: SharedStoreListener | null = null; | 37 | private listener: SharedStoreListener | null = null; |
38 | 38 | ||
@@ -71,26 +71,26 @@ class SophieRendererImpl implements SophieRenderer { | |||
71 | } | 71 | } |
72 | throw new Error('Failed to connect to shared store'); | 72 | throw new Error('Failed to connect to shared store'); |
73 | } | 73 | } |
74 | } | ||
74 | 75 | ||
75 | dispatchAction(actionToDispatch: Action): void { | 76 | function dispatchAction(actionToDispatch: Action): void { |
76 | // Let the full zod parse error bubble up to the main world, | 77 | // Let the full zod parse error bubble up to the main world, |
77 | // since all data it may contain was provided from the main world. | 78 | // since all data it may contain was provided from the main world. |
78 | const parsedAction = action.parse(actionToDispatch); | 79 | const parsedAction = action.parse(actionToDispatch); |
79 | try { | 80 | try { |
80 | ipcRenderer.send(RendererToMainIpcMessage.DispatchAction, parsedAction); | 81 | ipcRenderer.send(RendererToMainIpcMessage.DispatchAction, parsedAction); |
81 | } catch (err) { | 82 | } catch (err) { |
82 | // Do not leak IPC failure details into the main world. | 83 | // Do not leak IPC failure details into the main world. |
83 | const message = 'Failed to dispatch action'; | 84 | const message = 'Failed to dispatch action'; |
84 | log.error(message, actionToDispatch, err); | 85 | log.error(message, actionToDispatch, err); |
85 | throw new Error(message); | 86 | throw new Error(message); |
86 | } | ||
87 | } | 87 | } |
88 | } | 88 | } |
89 | 89 | ||
90 | export function createSophieRenderer(allowReplaceListener: boolean): SophieRenderer { | 90 | export default function createSophieRenderer(allowReplaceListener: boolean): SophieRenderer { |
91 | const impl = new SophieRendererImpl(allowReplaceListener); | 91 | const connector = new SharedStoreConnector(allowReplaceListener); |
92 | return { | 92 | return { |
93 | onSharedStoreChange: impl.onSharedStoreChange.bind(impl), | 93 | onSharedStoreChange: connector.onSharedStoreChange.bind(connector), |
94 | dispatchAction: impl.dispatchAction.bind(impl), | 94 | dispatchAction, |
95 | }; | 95 | }; |
96 | } | 96 | } |
diff --git a/packages/preload/src/index.ts b/packages/preload/src/index.ts index de91742..f13220c 100644 --- a/packages/preload/src/index.ts +++ b/packages/preload/src/index.ts | |||
@@ -20,7 +20,7 @@ | |||
20 | 20 | ||
21 | import { contextBridge } from 'electron'; | 21 | import { contextBridge } from 'electron'; |
22 | 22 | ||
23 | import { createSophieRenderer } from './contextBridge/SophieRendererImpl'; | 23 | import createSophieRenderer from './contextBridge/createSophieRenderer'; |
24 | 24 | ||
25 | const isDevelopment = import.meta.env.MODE === 'development'; | 25 | const isDevelopment = import.meta.env.MODE === 'development'; |
26 | 26 | ||
diff --git a/packages/preload/tsconfig.json b/packages/preload/tsconfig.json index 741d435..ff49538 100644 --- a/packages/preload/tsconfig.json +++ b/packages/preload/tsconfig.json | |||
@@ -1,5 +1,5 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "../../config/tsconfig.base.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "noEmit": true, | 4 | "noEmit": true, |
5 | "lib": [ | 5 | "lib": [ |
@@ -13,11 +13,13 @@ | |||
13 | }, | 13 | }, |
14 | "references": [ | 14 | "references": [ |
15 | { | 15 | { |
16 | "path": "../shared" | 16 | "path": "../shared/tsconfig.build.json" |
17 | } | 17 | } |
18 | ], | 18 | ], |
19 | "include": [ | 19 | "include": [ |
20 | "src/**/*.ts", | 20 | "src/**/*.ts", |
21 | "types/**/*.d.ts" | 21 | "types/**/*.d.ts", |
22 | "esbuild.config.js", | ||
23 | "jest.config.js" | ||
22 | ] | 24 | ] |
23 | } | 25 | } |
diff --git a/packages/renderer/.eslinrc.cjs b/packages/renderer/.eslinrc.cjs new file mode 100644 index 0000000..3385ac5 --- /dev/null +++ b/packages/renderer/.eslinrc.cjs | |||
@@ -0,0 +1,11 @@ | |||
1 | module.exports = { | ||
2 | extends: [ | ||
3 | 'airbnb', | ||
4 | 'airbnb/hooks', | ||
5 | 'airbnb-typescript', | ||
6 | ], | ||
7 | env: { | ||
8 | node: false, | ||
9 | browser: true, | ||
10 | }, | ||
11 | }; | ||
diff --git a/packages/renderer/.eslintrc.json b/packages/renderer/.eslintrc.json deleted file mode 100644 index a28aec9..0000000 --- a/packages/renderer/.eslintrc.json +++ /dev/null | |||
@@ -1,5 +0,0 @@ | |||
1 | { | ||
2 | "globals": { | ||
3 | "JSX": false | ||
4 | } | ||
5 | } | ||
diff --git a/packages/renderer/package.json b/packages/renderer/package.json index df15abb..fde4c28 100644 --- a/packages/renderer/package.json +++ b/packages/renderer/package.json | |||
@@ -5,7 +5,7 @@ | |||
5 | "type": "module", | 5 | "type": "module", |
6 | "types": "dist-types/index.d.ts", | 6 | "types": "dist-types/index.d.ts", |
7 | "scripts": { | 7 | "scripts": { |
8 | "typecheck": "tsc" | 8 | "typecheck:workspace": "yarn g:typecheck" |
9 | }, | 9 | }, |
10 | "dependencies": { | 10 | "dependencies": { |
11 | "@emotion/react": "^11.7.1", | 11 | "@emotion/react": "^11.7.1", |
@@ -14,7 +14,9 @@ | |||
14 | "@mui/icons-material": "^5.2.5", | 14 | "@mui/icons-material": "^5.2.5", |
15 | "@mui/material": "^5.2.7", | 15 | "@mui/material": "^5.2.7", |
16 | "@sophie/shared": "workspace:*", | 16 | "@sophie/shared": "workspace:*", |
17 | "lodash": "^4.17.21", | 17 | "lodash-es": "^4.17.21", |
18 | "loglevel": "^1.8.0", | ||
19 | "loglevel-plugin-prefix": "^0.8.4", | ||
18 | "mobx": "^6.3.12", | 20 | "mobx": "^6.3.12", |
19 | "mobx-react-lite": "^3.2.3", | 21 | "mobx-react-lite": "^3.2.3", |
20 | "mobx-state-tree": "^5.1.0", | 22 | "mobx-state-tree": "^5.1.0", |
@@ -22,14 +24,12 @@ | |||
22 | "react-dom": "^17.0.2" | 24 | "react-dom": "^17.0.2" |
23 | }, | 25 | }, |
24 | "devDependencies": { | 26 | "devDependencies": { |
25 | "@types/lodash": "^4.14.178", | 27 | "@types/lodash-es": "^4.14.178", |
26 | "@types/react": "^17.0.38", | 28 | "@types/react": "^17.0.38", |
27 | "@types/react-dom": "^17.0.11", | 29 | "@types/react-dom": "^17.0.11", |
28 | "@vitejs/plugin-react": "^1.1.4", | 30 | "@vitejs/plugin-react": "^1.1.4", |
29 | "mst-middlewares": "^5.1.0", | 31 | "mst-middlewares": "^5.1.0", |
30 | "remotedev": "^0.2.9", | 32 | "remotedev": "^0.2.9", |
31 | "rimraf": "^3.0.2", | ||
32 | "typescript": "^4.5.4", | ||
33 | "vite": "^2.7.10" | 33 | "vite": "^2.7.10" |
34 | } | 34 | } |
35 | } | 35 | } |
diff --git a/packages/renderer/src/components/App.tsx b/packages/renderer/src/components/App.tsx index 8bd3dd8..1174bbb 100644 --- a/packages/renderer/src/components/App.tsx +++ b/packages/renderer/src/components/App.tsx | |||
@@ -21,10 +21,10 @@ | |||
21 | import Box from '@mui/material/Box'; | 21 | import Box from '@mui/material/Box'; |
22 | import React from 'react'; | 22 | import React from 'react'; |
23 | 23 | ||
24 | import { BrowserViewPlaceholder } from './BrowserViewPlaceholder'; | 24 | import BrowserViewPlaceholder from './BrowserViewPlaceholder'; |
25 | import { Sidebar } from './Sidebar'; | 25 | import Sidebar from './Sidebar'; |
26 | 26 | ||
27 | export function App(): JSX.Element { | 27 | export default function App(): JSX.Element { |
28 | return ( | 28 | return ( |
29 | <Box | 29 | <Box |
30 | sx={{ | 30 | sx={{ |
diff --git a/packages/renderer/src/components/BrowserViewPlaceholder.tsx b/packages/renderer/src/components/BrowserViewPlaceholder.tsx index 6aa6b7b..c671983 100644 --- a/packages/renderer/src/components/BrowserViewPlaceholder.tsx +++ b/packages/renderer/src/components/BrowserViewPlaceholder.tsx | |||
@@ -18,17 +18,15 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { throttle } from 'lodash'; | ||
22 | import { observer } from 'mobx-react-lite'; | ||
23 | import Box from '@mui/material/Box'; | 21 | import Box from '@mui/material/Box'; |
22 | import throttle from 'lodash-es/throttle'; | ||
23 | import { observer } from 'mobx-react-lite'; | ||
24 | import React, { useCallback, useRef } from 'react'; | 24 | import React, { useCallback, useRef } from 'react'; |
25 | 25 | ||
26 | import { useStore } from './StoreProvider'; | 26 | import { useStore } from './StoreProvider'; |
27 | 27 | ||
28 | export const BrowserViewPlaceholder = observer(function BrowserViewPlaceholder() { | 28 | export default observer(() => { |
29 | const { | 29 | const store = useStore(); |
30 | setBrowserViewBounds, | ||
31 | } = useStore(); | ||
32 | 30 | ||
33 | const onResize = useCallback(throttle(([entry]: ResizeObserverEntry[]) => { | 31 | const onResize = useCallback(throttle(([entry]: ResizeObserverEntry[]) => { |
34 | if (entry) { | 32 | if (entry) { |
@@ -38,14 +36,14 @@ export const BrowserViewPlaceholder = observer(function BrowserViewPlaceholder() | |||
38 | width, | 36 | width, |
39 | height, | 37 | height, |
40 | } = entry.target.getBoundingClientRect(); | 38 | } = entry.target.getBoundingClientRect(); |
41 | setBrowserViewBounds({ | 39 | store.setBrowserViewBounds({ |
42 | x, | 40 | x, |
43 | y, | 41 | y, |
44 | width, | 42 | width, |
45 | height, | 43 | height, |
46 | }); | 44 | }); |
47 | } | 45 | } |
48 | }, 100), [setBrowserViewBounds]); | 46 | }, 100), [store]); |
49 | 47 | ||
50 | const resizeObserverRef = useRef<ResizeObserver | null>(null); | 48 | const resizeObserverRef = useRef<ResizeObserver | null>(null); |
51 | 49 | ||
diff --git a/packages/renderer/src/components/Sidebar.tsx b/packages/renderer/src/components/Sidebar.tsx index 6c79932..44a47b0 100644 --- a/packages/renderer/src/components/Sidebar.tsx +++ b/packages/renderer/src/components/Sidebar.tsx | |||
@@ -21,9 +21,9 @@ | |||
21 | import Box from '@mui/material/Box'; | 21 | import Box from '@mui/material/Box'; |
22 | import React from 'react'; | 22 | import React from 'react'; |
23 | 23 | ||
24 | import { ToggleDarkModeButton } from './ToggleDarkModeButton'; | 24 | import ToggleDarkModeButton from './ToggleDarkModeButton'; |
25 | 25 | ||
26 | export function Sidebar(): JSX.Element { | 26 | export default function Sidebar(): JSX.Element { |
27 | return ( | 27 | return ( |
28 | <Box | 28 | <Box |
29 | sx={(theme) => ({ | 29 | sx={(theme) => ({ |
diff --git a/packages/renderer/src/components/StoreProvider.tsx b/packages/renderer/src/components/StoreProvider.tsx index da1e699..cde6a31 100644 --- a/packages/renderer/src/components/StoreProvider.tsx +++ b/packages/renderer/src/components/StoreProvider.tsx | |||
@@ -32,7 +32,7 @@ export function useStore(): RendererStore { | |||
32 | return store; | 32 | return store; |
33 | } | 33 | } |
34 | 34 | ||
35 | export function StoreProvider({ children, store }: { | 35 | export default function StoreProvider({ children, store }: { |
36 | children: JSX.Element | JSX.Element[], | 36 | children: JSX.Element | JSX.Element[], |
37 | store: RendererStore, | 37 | store: RendererStore, |
38 | }): JSX.Element { | 38 | }): JSX.Element { |
diff --git a/packages/renderer/src/components/ThemeProvider.tsx b/packages/renderer/src/components/ThemeProvider.tsx index 9215f5c..eacaa52 100644 --- a/packages/renderer/src/components/ThemeProvider.tsx +++ b/packages/renderer/src/components/ThemeProvider.tsx | |||
@@ -18,18 +18,18 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { observer } from 'mobx-react-lite'; | ||
22 | import { | 21 | import { |
23 | unstable_createMuiStrictModeTheme as createTheme, | 22 | unstable_createMuiStrictModeTheme as createTheme, |
24 | ThemeProvider as MuiThemeProvider, | 23 | ThemeProvider as MuiThemeProvider, |
25 | } from '@mui/material/styles'; | 24 | } from '@mui/material/styles'; |
25 | import { observer } from 'mobx-react-lite'; | ||
26 | import React from 'react'; | 26 | import React from 'react'; |
27 | 27 | ||
28 | import { useStore } from './StoreProvider'; | 28 | import { useStore } from './StoreProvider'; |
29 | 29 | ||
30 | export const ThemeProvider = observer(function ThemeProvider({ children }: { | 30 | export default observer(({ children }: { |
31 | children: JSX.Element | JSX.Element[], | 31 | children: JSX.Element | JSX.Element[]; |
32 | }) { | 32 | }) => { |
33 | const { shared: { shouldUseDarkColors } } = useStore(); | 33 | const { shared: { shouldUseDarkColors } } = useStore(); |
34 | 34 | ||
35 | const theme = createTheme({ | 35 | const theme = createTheme({ |
diff --git a/packages/renderer/src/components/ToggleDarkModeButton.tsx b/packages/renderer/src/components/ToggleDarkModeButton.tsx index 1b6757e..c8ffdf0 100644 --- a/packages/renderer/src/components/ToggleDarkModeButton.tsx +++ b/packages/renderer/src/components/ToggleDarkModeButton.tsx | |||
@@ -18,21 +18,22 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { observer } from 'mobx-react-lite'; | ||
22 | import DarkModeIcon from '@mui/icons-material/DarkMode'; | 21 | import DarkModeIcon from '@mui/icons-material/DarkMode'; |
23 | import LightModeIcon from '@mui/icons-material/LightMode'; | 22 | import LightModeIcon from '@mui/icons-material/LightMode'; |
24 | import IconButton from '@mui/material/IconButton'; | 23 | import IconButton from '@mui/material/IconButton'; |
24 | import { observer } from 'mobx-react-lite'; | ||
25 | import React from 'react'; | 25 | import React from 'react'; |
26 | 26 | ||
27 | import { useStore } from './StoreProvider'; | 27 | import { useStore } from './StoreProvider'; |
28 | 28 | ||
29 | export const ToggleDarkModeButton = observer(function ToggleDarkModeButton() { | 29 | export default observer(() => { |
30 | const { shared: { shouldUseDarkColors }, toggleDarkMode } = useStore(); | 30 | const store = useStore(); |
31 | const { shared: { shouldUseDarkColors } } = store; | ||
31 | 32 | ||
32 | return ( | 33 | return ( |
33 | <IconButton | 34 | <IconButton |
34 | aria-label="Toggle dark mode" | 35 | aria-label="Toggle dark mode" |
35 | onClick={() => toggleDarkMode()} | 36 | onClick={() => store.toggleDarkMode()} |
36 | > | 37 | > |
37 | {shouldUseDarkColors ? <LightModeIcon /> : <DarkModeIcon />} | 38 | {shouldUseDarkColors ? <LightModeIcon /> : <DarkModeIcon />} |
38 | </IconButton> | 39 | </IconButton> |
diff --git a/packages/renderer/src/devTools.ts b/packages/renderer/src/devTools.ts index 3ec66aa..3d3ba99 100644 --- a/packages/renderer/src/devTools.ts +++ b/packages/renderer/src/devTools.ts | |||
@@ -32,31 +32,24 @@ import type { IAnyStateTreeNode } from 'mobx-state-tree'; | |||
32 | * However, we don't bundle `remotedev` in production, so the call would fail anyways. | 32 | * However, we don't bundle `remotedev` in production, so the call would fail anyways. |
33 | * | 33 | * |
34 | * @param model The store to connect to the redux devtools. | 34 | * @param model The store to connect to the redux devtools. |
35 | * @return A promise that resolves when the store was exposed to the devtools. | ||
35 | * @see https://github.com/SocketCluster/socketcluster-client/issues/118#issuecomment-469064682 | 36 | * @see https://github.com/SocketCluster/socketcluster-client/issues/118#issuecomment-469064682 |
36 | */ | 37 | */ |
37 | async function exposeToReduxDevtoolsAsync(model: IAnyStateTreeNode): Promise<void> { | 38 | export async function exposeToReduxDevtools(model: IAnyStateTreeNode): Promise<void> { |
38 | (window as { global?: unknown }).global = window; | 39 | (window as { global?: unknown }).global = window; |
39 | 40 | ||
41 | // Hack to load dev dependencies on demand. | ||
40 | const [remotedev, { connectReduxDevtools }] = await Promise.all([ | 42 | const [remotedev, { connectReduxDevtools }] = await Promise.all([ |
41 | // @ts-ignore | 43 | // @ts-expect-error `remotedev` has no typings. |
42 | import('remotedev'), | 44 | // eslint-disable-next-line import/no-extraneous-dependencies |
45 | import('remotedev') as unknown, | ||
46 | // eslint-disable-next-line import/no-extraneous-dependencies | ||
43 | import('mst-middlewares'), | 47 | import('mst-middlewares'), |
44 | ]); | 48 | ]); |
45 | connectReduxDevtools(remotedev, model); | 49 | connectReduxDevtools(remotedev, model); |
46 | } | 50 | } |
47 | 51 | ||
48 | /** | 52 | /** |
49 | * Connects the `model` to the redux devtools extension. | ||
50 | * | ||
51 | * @param model The store to connect to the redux devtools. | ||
52 | */ | ||
53 | export function exposeToReduxDevtools(model: IAnyStateTreeNode): void { | ||
54 | exposeToReduxDevtoolsAsync(model).catch((err) => { | ||
55 | console.error('Could not connect to Redux devtools', err); | ||
56 | }); | ||
57 | } | ||
58 | |||
59 | /** | ||
60 | * Sends a message to the main process to reload all services when | 53 | * Sends a message to the main process to reload all services when |
61 | * `build/watch.js` sends a reload event on bundle write. | 54 | * `build/watch.js` sends a reload event on bundle write. |
62 | */ | 55 | */ |
diff --git a/packages/renderer/src/index.tsx b/packages/renderer/src/index.tsx index 1626bef..d900e50 100644 --- a/packages/renderer/src/index.tsx +++ b/packages/renderer/src/index.tsx | |||
@@ -26,14 +26,17 @@ import CssBaseline from '@mui/material/CssBaseline'; | |||
26 | import React from 'react'; | 26 | import React from 'react'; |
27 | import { render } from 'react-dom'; | 27 | import { render } from 'react-dom'; |
28 | 28 | ||
29 | import { App } from './components/App'; | 29 | import App from './components/App'; |
30 | import { StoreProvider } from './components/StoreProvider'; | 30 | import StoreProvider from './components/StoreProvider'; |
31 | import { ThemeProvider } from './components/ThemeProvider'; | 31 | import ThemeProvider from './components/ThemeProvider'; |
32 | import { exposeToReduxDevtools, hotReloadServices } from './devTools'; | 32 | import { exposeToReduxDevtools, hotReloadServices } from './devTools'; |
33 | import { createAndConnectRendererStore } from './stores/RendererStore'; | 33 | import { createAndConnectRendererStore } from './stores/RendererStore'; |
34 | import { getLogger } from './utils/log'; | ||
34 | 35 | ||
35 | const isDevelopment = import.meta.env.MODE === 'development'; | 36 | const isDevelopment = import.meta.env.MODE === 'development'; |
36 | 37 | ||
38 | const log = getLogger('index'); | ||
39 | |||
37 | if (isDevelopment) { | 40 | if (isDevelopment) { |
38 | hotReloadServices(); | 41 | hotReloadServices(); |
39 | document.title = `[dev] ${document.title}`; | 42 | document.title = `[dev] ${document.title}`; |
@@ -42,7 +45,9 @@ if (isDevelopment) { | |||
42 | const store = createAndConnectRendererStore(window.sophieRenderer); | 45 | const store = createAndConnectRendererStore(window.sophieRenderer); |
43 | 46 | ||
44 | if (isDevelopment) { | 47 | if (isDevelopment) { |
45 | exposeToReduxDevtools(store); | 48 | exposeToReduxDevtools(store).catch((err) => { |
49 | log.error('Cannot initialize redux devtools', err); | ||
50 | }); | ||
46 | } | 51 | } |
47 | 52 | ||
48 | function Root(): JSX.Element { | 53 | function Root(): JSX.Element { |
diff --git a/packages/renderer/src/stores/RendererEnv.ts b/packages/renderer/src/stores/RendererEnv.ts index d687738..f0a5a51 100644 --- a/packages/renderer/src/stores/RendererEnv.ts +++ b/packages/renderer/src/stores/RendererEnv.ts | |||
@@ -18,10 +18,10 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { getEnv as getAnyEnv, IAnyStateTreeNode } from 'mobx-state-tree'; | ||
22 | import type { Action } from '@sophie/shared'; | 21 | import type { Action } from '@sophie/shared'; |
22 | import { getEnv as getAnyEnv, IAnyStateTreeNode } from 'mobx-state-tree'; | ||
23 | 23 | ||
24 | export interface RendererEnv { | 24 | export default interface RendererEnv { |
25 | dispatchMainAction(action: Action): void; | 25 | dispatchMainAction(action: Action): void; |
26 | } | 26 | } |
27 | 27 | ||
diff --git a/packages/renderer/src/stores/RendererStore.ts b/packages/renderer/src/stores/RendererStore.ts index 037b212..e684759 100644 --- a/packages/renderer/src/stores/RendererStore.ts +++ b/packages/renderer/src/stores/RendererStore.ts | |||
@@ -19,19 +19,24 @@ | |||
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { | 21 | import { |
22 | applySnapshot, | ||
23 | applyPatch, | ||
24 | Instance, | ||
25 | types, | ||
26 | } from 'mobx-state-tree'; | ||
27 | import { | ||
28 | BrowserViewBounds, | 22 | BrowserViewBounds, |
29 | sharedStore, | 23 | sharedStore, |
30 | SophieRenderer, | 24 | SophieRenderer, |
31 | ThemeSource, | 25 | ThemeSource, |
32 | } from '@sophie/shared'; | 26 | } from '@sophie/shared'; |
27 | import { | ||
28 | applySnapshot, | ||
29 | applyPatch, | ||
30 | Instance, | ||
31 | types, | ||
32 | } from 'mobx-state-tree'; | ||
33 | |||
34 | import { getLogger } from '../utils/log'; | ||
35 | |||
36 | import type RendererEnv from './RendererEnv'; | ||
37 | import { getEnv } from './RendererEnv'; | ||
33 | 38 | ||
34 | import { getEnv, RendererEnv } from './RendererEnv'; | 39 | const log = getLogger('RendererStore'); |
35 | 40 | ||
36 | export const rendererStore = types.model('RendererStore', { | 41 | export const rendererStore = types.model('RendererStore', { |
37 | shared: types.optional(sharedStore, {}), | 42 | shared: types.optional(sharedStore, {}), |
@@ -81,7 +86,7 @@ export function createAndConnectRendererStore(ipc: SophieRenderer): RendererStor | |||
81 | applyPatch(store.shared, patch); | 86 | applyPatch(store.shared, patch); |
82 | }, | 87 | }, |
83 | }).catch((err) => { | 88 | }).catch((err) => { |
84 | console.error('Failed to connect to shared store', err); | 89 | log.error('Failed to connect to shared store', err); |
85 | }); | 90 | }); |
86 | 91 | ||
87 | return store; | 92 | return store; |
diff --git a/packages/renderer/src/utils/log.ts b/packages/renderer/src/utils/log.ts new file mode 100644 index 0000000..c17fc2a --- /dev/null +++ b/packages/renderer/src/utils/log.ts | |||
@@ -0,0 +1,50 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com> | ||
3 | * | ||
4 | * This file is part of Sophie. | ||
5 | * | ||
6 | * Sophie is free software: you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Affero General Public License as | ||
8 | * published by the Free Software Foundation, version 3. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Affero General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Affero General Public License | ||
16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * SPDX-License-Identifier: AGPL-3.0-only | ||
19 | */ | ||
20 | |||
21 | import loglevel, { Logger } from 'loglevel'; | ||
22 | import prefix from 'loglevel-plugin-prefix'; | ||
23 | |||
24 | if (import.meta.env?.DEV) { | ||
25 | loglevel.setLevel('debug'); | ||
26 | } else { | ||
27 | // No devtools in production, so there's not point to log anything. | ||
28 | loglevel.disableAll(); | ||
29 | } | ||
30 | |||
31 | prefix.reg(loglevel); | ||
32 | prefix.apply(loglevel, { | ||
33 | format(level, name, timestamp) { | ||
34 | const timeStr = timestamp.toString(); | ||
35 | const nameStr = typeof name === 'undefined' ? '' : ` ${name}`; | ||
36 | return `[${timeStr}] ${level}${nameStr}:`; | ||
37 | }, | ||
38 | }); | ||
39 | |||
40 | export function getLogger(loggerName: string): Logger { | ||
41 | return loglevel.getLogger(loggerName); | ||
42 | } | ||
43 | |||
44 | export function silenceLogger(): void { | ||
45 | loglevel.disableAll(); | ||
46 | const loggers = loglevel.getLoggers(); | ||
47 | Object.keys(loggers).forEach((loggerName) => { | ||
48 | loggers[loggerName].disableAll(); | ||
49 | }); | ||
50 | } | ||
diff --git a/packages/renderer/tsconfig.json b/packages/renderer/tsconfig.json index 8746462..14c3e0c 100644 --- a/packages/renderer/tsconfig.json +++ b/packages/renderer/tsconfig.json | |||
@@ -1,5 +1,5 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "../../config/tsconfig.base.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "noEmit": true, | 4 | "noEmit": true, |
5 | "jsx": "react", | 5 | "jsx": "react", |
@@ -14,12 +14,14 @@ | |||
14 | }, | 14 | }, |
15 | "references": [ | 15 | "references": [ |
16 | { | 16 | { |
17 | "path": "../shared" | 17 | "path": "../shared/tsconfig.build.json" |
18 | } | 18 | } |
19 | ], | 19 | ], |
20 | "include": [ | 20 | "include": [ |
21 | "src/**/*.ts", | 21 | "src/**/*.ts", |
22 | "src/**/*.tsx", | 22 | "src/**/*.tsx", |
23 | "types/**/*.d.ts" | 23 | "types/**/*.d.ts", |
24 | ".eslintrc.cjs", | ||
25 | "vite.config.js" | ||
24 | ] | 26 | ] |
25 | } | 27 | } |
diff --git a/packages/renderer/vite.config.js b/packages/renderer/vite.config.js index bcd1975..6440ead 100644 --- a/packages/renderer/vite.config.js +++ b/packages/renderer/vite.config.js | |||
@@ -3,10 +3,11 @@ | |||
3 | 3 | ||
4 | import { builtinModules } from 'module'; | 4 | import { builtinModules } from 'module'; |
5 | import { join } from 'path'; | 5 | import { join } from 'path'; |
6 | |||
6 | import react from '@vitejs/plugin-react'; | 7 | import react from '@vitejs/plugin-react'; |
7 | 8 | ||
8 | import { banner, chrome } from '../../config/buildConstants.js'; | 9 | import { banner, chrome } from '../../config/buildConstants.js'; |
9 | import { fileURLToDirname } from '../../config/utils.js'; | 10 | import fileURLToDirname from '../../config/fileURLToDirname.js'; |
10 | 11 | ||
11 | const thisDir = fileURLToDirname(import.meta.url); | 12 | const thisDir = fileURLToDirname(import.meta.url); |
12 | 13 | ||
@@ -45,7 +46,7 @@ export default { | |||
45 | preserveSymlinks: true, | 46 | preserveSymlinks: true, |
46 | }, | 47 | }, |
47 | optimizeDeps: { | 48 | optimizeDeps: { |
48 | link: [ | 49 | exclude: [ |
49 | '@sophie/shared', | 50 | '@sophie/shared', |
50 | ], | 51 | ], |
51 | }, | 52 | }, |
diff --git a/packages/service-inject/.eslintrc.cjs b/packages/service-inject/.eslintrc.cjs new file mode 100644 index 0000000..6ae3faf --- /dev/null +++ b/packages/service-inject/.eslintrc.cjs | |||
@@ -0,0 +1,6 @@ | |||
1 | module.exports = { | ||
2 | env: { | ||
3 | node: false, | ||
4 | browser: true, | ||
5 | }, | ||
6 | }; | ||
diff --git a/packages/service-inject/esbuild.config.js b/packages/service-inject/esbuild.config.js index 2169c8e..d0b04bb 100644 --- a/packages/service-inject/esbuild.config.js +++ b/packages/service-inject/esbuild.config.js | |||
@@ -1,8 +1,8 @@ | |||
1 | import { chrome } from '../../config/buildConstants.js'; | 1 | import { chrome } from '../../config/buildConstants.js'; |
2 | import { getConfig } from '../../config/esbuildConfig.js'; | 2 | import fileURLToDirname from '../../config/fileURLToDirname.js'; |
3 | import { fileURLToDirname } from '../../config/utils.js'; | 3 | import getEsbuildConfig from '../../config/getEsbuildConfig.js'; |
4 | 4 | ||
5 | export default getConfig({ | 5 | export default getEsbuildConfig({ |
6 | absWorkingDir: fileURLToDirname(import.meta.url), | 6 | absWorkingDir: fileURLToDirname(import.meta.url), |
7 | entryPoints: [ | 7 | entryPoints: [ |
8 | 'src/index.ts', | 8 | 'src/index.ts', |
diff --git a/packages/service-inject/package.json b/packages/service-inject/package.json index 7c496fd..c045500 100644 --- a/packages/service-inject/package.json +++ b/packages/service-inject/package.json | |||
@@ -6,13 +6,9 @@ | |||
6 | "type": "module", | 6 | "type": "module", |
7 | "types": "dist-types/index.d.ts", | 7 | "types": "dist-types/index.d.ts", |
8 | "scripts": { | 8 | "scripts": { |
9 | "typecheck": "tsc" | 9 | "typecheck:workspace": "yarn g:typecheck" |
10 | }, | 10 | }, |
11 | "dependencies": { | 11 | "dependencies": { |
12 | "@sophie/service-shared": "workspace:*" | 12 | "@sophie/service-shared": "workspace:*" |
13 | }, | ||
14 | "devDependencies": { | ||
15 | "rimraf": "^3.0.2", | ||
16 | "typescript": "^4.5.4" | ||
17 | } | 13 | } |
18 | } | 14 | } |
diff --git a/packages/service-inject/tsconfig.json b/packages/service-inject/tsconfig.json index 638690b..cc61d63 100644 --- a/packages/service-inject/tsconfig.json +++ b/packages/service-inject/tsconfig.json | |||
@@ -1,5 +1,5 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "../../config/tsconfig.base.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "noEmit": true, | 4 | "noEmit": true, |
5 | "lib": [ | 5 | "lib": [ |
@@ -10,10 +10,11 @@ | |||
10 | }, | 10 | }, |
11 | "references": [ | 11 | "references": [ |
12 | { | 12 | { |
13 | "path": "../service-shared" | 13 | "path": "../service-shared/tsconfig.build.json" |
14 | } | 14 | } |
15 | ], | 15 | ], |
16 | "include": [ | 16 | "include": [ |
17 | "src/**/*.ts" | 17 | "src/**/*.ts", |
18 | "esbuild.config.js" | ||
18 | ] | 19 | ] |
19 | } | 20 | } |
diff --git a/packages/service-preload/.eslintrc.cjs b/packages/service-preload/.eslintrc.cjs new file mode 100644 index 0000000..02fab21 --- /dev/null +++ b/packages/service-preload/.eslintrc.cjs | |||
@@ -0,0 +1,6 @@ | |||
1 | module.exports = { | ||
2 | env: { | ||
3 | node: true, | ||
4 | browser: true, | ||
5 | }, | ||
6 | }; | ||
diff --git a/packages/service-preload/esbuild.config.js b/packages/service-preload/esbuild.config.js index b73a071..66f5e84 100644 --- a/packages/service-preload/esbuild.config.js +++ b/packages/service-preload/esbuild.config.js | |||
@@ -1,8 +1,8 @@ | |||
1 | import { chrome } from '../../config/buildConstants.js'; | 1 | import { chrome } from '../../config/buildConstants.js'; |
2 | import { getConfig } from '../../config/esbuildConfig.js'; | 2 | import fileURLToDirname from '../../config/fileURLToDirname.js'; |
3 | import { fileURLToDirname } from '../../config/utils.js'; | 3 | import getEsbuildConfig from '../../config/getEsbuildConfig.js'; |
4 | 4 | ||
5 | export default getConfig({ | 5 | export default getEsbuildConfig({ |
6 | absWorkingDir: fileURLToDirname(import.meta.url), | 6 | absWorkingDir: fileURLToDirname(import.meta.url), |
7 | entryPoints: [ | 7 | entryPoints: [ |
8 | 'src/index.ts', | 8 | 'src/index.ts', |
diff --git a/packages/service-preload/package.json b/packages/service-preload/package.json index 26215a3..14717f8 100644 --- a/packages/service-preload/package.json +++ b/packages/service-preload/package.json | |||
@@ -5,14 +5,12 @@ | |||
5 | "type": "module", | 5 | "type": "module", |
6 | "types": "dist-types/index.d.ts", | 6 | "types": "dist-types/index.d.ts", |
7 | "scripts": { | 7 | "scripts": { |
8 | "typecheck": "tsc" | 8 | "typecheck:workspace": "yarn g:typecheck" |
9 | }, | 9 | }, |
10 | "dependencies": { | 10 | "dependencies": { |
11 | "@sophie/service-shared": "workspace:*", | 11 | "@sophie/service-shared": "workspace:*", |
12 | "electron": "16.0.6" | 12 | "electron": "16.0.6", |
13 | }, | 13 | "loglevel": "^1.8.0", |
14 | "devDependencies": { | 14 | "loglevel-plugin-prefix": "^0.8.4" |
15 | "rimraf": "^3.0.2", | ||
16 | "typescript": "^4.5.4" | ||
17 | } | 15 | } |
18 | } | 16 | } |
diff --git a/packages/service-preload/src/index.ts b/packages/service-preload/src/index.ts index d1ea13c..2bbfefd 100644 --- a/packages/service-preload/src/index.ts +++ b/packages/service-preload/src/index.ts | |||
@@ -18,8 +18,12 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { ipcRenderer, webFrame } from 'electron'; | ||
22 | import { ServiceToMainIpcMessage, webSource } from '@sophie/service-shared'; | 21 | import { ServiceToMainIpcMessage, webSource } from '@sophie/service-shared'; |
22 | import { ipcRenderer, webFrame } from 'electron'; | ||
23 | |||
24 | import { getLogger } from './utils/log'; | ||
25 | |||
26 | const log = getLogger('index'); | ||
23 | 27 | ||
24 | if (webFrame.parent === null) { | 28 | if (webFrame.parent === null) { |
25 | // Inject CSS to simulate `browserView.setBackgroundColor`. | 29 | // Inject CSS to simulate `browserView.setBackgroundColor`. |
@@ -49,14 +53,14 @@ if (webFrame.parent === null) { | |||
49 | * @see https://www.electronjs.org/docs/latest/api/web-contents#contentsexecutejavascriptinisolatedworldworldid-scripts-usergesture | 53 | * @see https://www.electronjs.org/docs/latest/api/web-contents#contentsexecutejavascriptinisolatedworldworldid-scripts-usergesture |
50 | */ | 54 | */ |
51 | async function fetchAndExecuteInjectScript(): Promise<void> { | 55 | async function fetchAndExecuteInjectScript(): Promise<void> { |
52 | const apiExposedResponse = await ipcRenderer.invoke( | 56 | const apiExposedResponse: unknown = await ipcRenderer.invoke( |
53 | ServiceToMainIpcMessage.ApiExposedInMainWorld, | 57 | ServiceToMainIpcMessage.ApiExposedInMainWorld, |
54 | ); | 58 | ); |
55 | const injectSource = webSource.parse(apiExposedResponse); | 59 | const injectSource = webSource.parse(apiExposedResponse); |
56 | // Isolated world 0 is the main world. | 60 | // Isolated world 0 is the main world. |
57 | return webFrame.executeJavaScriptInIsolatedWorld(0, [injectSource]); | 61 | await webFrame.executeJavaScriptInIsolatedWorld(0, [injectSource]); |
58 | } | 62 | } |
59 | 63 | ||
60 | fetchAndExecuteInjectScript().catch((err) => { | 64 | fetchAndExecuteInjectScript().catch((err) => { |
61 | console.log('Failed to fetch inject source:', err); | 65 | log.error('Failed to fetch inject source:', err); |
62 | }); | 66 | }); |
diff --git a/packages/service-preload/src/utils/log.ts b/packages/service-preload/src/utils/log.ts new file mode 100644 index 0000000..0c35319 --- /dev/null +++ b/packages/service-preload/src/utils/log.ts | |||
@@ -0,0 +1,49 @@ | |||
1 | /* | ||
2 | * Copyright (C) 2022 Kristóf Marussy <kristof@marussy.com> | ||
3 | * | ||
4 | * This file is part of Sophie. | ||
5 | * | ||
6 | * Sophie is free software: you can redistribute it and/or modify | ||
7 | * it under the terms of the GNU Affero General Public License as | ||
8 | * published by the Free Software Foundation, version 3. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, | ||
11 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU Affero General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU Affero General Public License | ||
16 | * along with this program. If not, see <https://www.gnu.org/licenses/>. | ||
17 | * | ||
18 | * SPDX-License-Identifier: AGPL-3.0-only | ||
19 | */ | ||
20 | |||
21 | import loglevel, { Logger } from 'loglevel'; | ||
22 | import prefix from 'loglevel-plugin-prefix'; | ||
23 | |||
24 | if (import.meta.env?.DEV) { | ||
25 | loglevel.setLevel('debug'); | ||
26 | } else { | ||
27 | loglevel.setLevel('info'); | ||
28 | } | ||
29 | |||
30 | prefix.reg(loglevel); | ||
31 | prefix.apply(loglevel, { | ||
32 | format(level, name, timestamp) { | ||
33 | const timeStr = timestamp.toString(); | ||
34 | const nameStr = typeof name === 'undefined' ? '' : ` ${name}`; | ||
35 | return `[${timeStr}] ${level}${nameStr}:`; | ||
36 | }, | ||
37 | }); | ||
38 | |||
39 | export function getLogger(loggerName: string): Logger { | ||
40 | return loglevel.getLogger(loggerName); | ||
41 | } | ||
42 | |||
43 | export function silenceLogger(): void { | ||
44 | loglevel.disableAll(); | ||
45 | const loggers = loglevel.getLoggers(); | ||
46 | Object.keys(loggers).forEach((loggerName) => { | ||
47 | loggers[loggerName].disableAll(); | ||
48 | }); | ||
49 | } | ||
diff --git a/packages/service-preload/tsconfig.json b/packages/service-preload/tsconfig.json index 638690b..0372dde 100644 --- a/packages/service-preload/tsconfig.json +++ b/packages/service-preload/tsconfig.json | |||
@@ -1,5 +1,5 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "../../config/tsconfig.base.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "noEmit": true, | 4 | "noEmit": true, |
5 | "lib": [ | 5 | "lib": [ |
@@ -10,10 +10,12 @@ | |||
10 | }, | 10 | }, |
11 | "references": [ | 11 | "references": [ |
12 | { | 12 | { |
13 | "path": "../service-shared" | 13 | "path": "../service-shared/tsconfig.build.json" |
14 | } | 14 | } |
15 | ], | 15 | ], |
16 | "include": [ | 16 | "include": [ |
17 | "src/**/*.ts" | 17 | "src/**/*.ts", |
18 | "types/**/*.ts", | ||
19 | "esbuild.config.js" | ||
18 | ] | 20 | ] |
19 | } | 21 | } |
diff --git a/packages/service-preload/types/importMeta.d.ts b/packages/service-preload/types/importMeta.d.ts new file mode 100644 index 0000000..9b73170 --- /dev/null +++ b/packages/service-preload/types/importMeta.d.ts | |||
@@ -0,0 +1,7 @@ | |||
1 | interface ImportMeta { | ||
2 | env: { | ||
3 | DEV: boolean; | ||
4 | MODE: string; | ||
5 | PROD: boolean; | ||
6 | } | ||
7 | } | ||
diff --git a/packages/service-shared/.eslintrc.cjs b/packages/service-shared/.eslintrc.cjs new file mode 100644 index 0000000..71d6ec4 --- /dev/null +++ b/packages/service-shared/.eslintrc.cjs | |||
@@ -0,0 +1,7 @@ | |||
1 | module.exports = { | ||
2 | env: { | ||
3 | // We must run in both node and browser, so we can't depend on either of them. | ||
4 | node: false, | ||
5 | browser: false, | ||
6 | }, | ||
7 | }; | ||
diff --git a/packages/service-shared/esbuild.config.js b/packages/service-shared/esbuild.config.js index 08941a4..ccee72c 100644 --- a/packages/service-shared/esbuild.config.js +++ b/packages/service-shared/esbuild.config.js | |||
@@ -1,8 +1,8 @@ | |||
1 | import { chrome, node } from '../../config/buildConstants.js'; | 1 | import { chrome, node } from '../../config/buildConstants.js'; |
2 | import { getConfig } from '../../config/esbuildConfig.js'; | 2 | import fileURLToDirname from '../../config/fileURLToDirname.js'; |
3 | import { fileURLToDirname } from '../../config/utils.js'; | 3 | import getEsbuildConfig from '../../config/getEsbuildConfig.js'; |
4 | 4 | ||
5 | export default getConfig({ | 5 | export default getEsbuildConfig({ |
6 | absWorkingDir: fileURLToDirname(import.meta.url), | 6 | absWorkingDir: fileURLToDirname(import.meta.url), |
7 | entryPoints: [ | 7 | entryPoints: [ |
8 | 'src/index.ts', | 8 | 'src/index.ts', |
diff --git a/packages/service-shared/package.json b/packages/service-shared/package.json index 9d75fc8..5338c8c 100644 --- a/packages/service-shared/package.json +++ b/packages/service-shared/package.json | |||
@@ -7,13 +7,10 @@ | |||
7 | "exports": "./dist/index.mjs", | 7 | "exports": "./dist/index.mjs", |
8 | "types": "dist/index.d.ts", | 8 | "types": "dist/index.d.ts", |
9 | "scripts": { | 9 | "scripts": { |
10 | "typecheck": "tsc" | 10 | "typecheck:workspace": "yarn g:typecheck", |
11 | "types": "yarn g:types" | ||
11 | }, | 12 | }, |
12 | "dependencies": { | 13 | "dependencies": { |
13 | "zod": "^3.11.6" | 14 | "zod": "^3.11.6" |
14 | }, | ||
15 | "devDependencies": { | ||
16 | "rimraf": "^3.0.2", | ||
17 | "typescript": "^4.5.4" | ||
18 | } | 15 | } |
19 | } | 16 | } |
diff --git a/packages/service-shared/src/index.ts b/packages/service-shared/src/index.ts index 564ebe8..e111347 100644 --- a/packages/service-shared/src/index.ts +++ b/packages/service-shared/src/index.ts | |||
@@ -18,7 +18,7 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | export { ServiceToMainIpcMessage } from './ipc'; | 21 | export { MainToServiceIpcMessage, ServiceToMainIpcMessage } from './ipc'; |
22 | 22 | ||
23 | export type { | 23 | export type { |
24 | UnreadCount, | 24 | UnreadCount, |
diff --git a/packages/service-shared/src/ipc.ts b/packages/service-shared/src/ipc.ts index 4f991c5..c0dab11 100644 --- a/packages/service-shared/src/ipc.ts +++ b/packages/service-shared/src/ipc.ts | |||
@@ -18,6 +18,9 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | export enum MainToServiceIpcMessage { | ||
22 | } | ||
23 | |||
21 | export enum ServiceToMainIpcMessage { | 24 | export enum ServiceToMainIpcMessage { |
22 | ApiExposedInMainWorld = 'sophie-service-to-main:api-exposed-in-main-world', | 25 | ApiExposedInMainWorld = 'sophie-service-to-main:api-exposed-in-main-world', |
23 | SetUnreadCount = 'sophie-service-to-main:set-unread-count', | 26 | SetUnreadCount = 'sophie-service-to-main:set-unread-count', |
diff --git a/packages/service-shared/tsconfig.build.json b/packages/service-shared/tsconfig.build.json new file mode 100644 index 0000000..9a0c835 --- /dev/null +++ b/packages/service-shared/tsconfig.build.json | |||
@@ -0,0 +1,12 @@ | |||
1 | { | ||
2 | "extends": "../../config/tsconfig.base.json", | ||
3 | "compilerOptions": { | ||
4 | "composite": true, | ||
5 | "declarationDir": "dist", | ||
6 | "emitDeclarationOnly": true, | ||
7 | "rootDir": "src" | ||
8 | }, | ||
9 | "include": [ | ||
10 | "src/**/*.ts" | ||
11 | ] | ||
12 | } | ||
diff --git a/packages/service-shared/tsconfig.json b/packages/service-shared/tsconfig.json index ff5a29b..79889d2 100644 --- a/packages/service-shared/tsconfig.json +++ b/packages/service-shared/tsconfig.json | |||
@@ -1,12 +1,14 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "./tsconfig.build.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "composite": true, | 4 | "composite": false, |
5 | "declarationDir": "dist", | 5 | "emitDeclarationOnly": false, |
6 | "emitDeclarationOnly": true, | 6 | "declarationDir": null, |
7 | "rootDir": "src" | 7 | "noEmit": true, |
8 | "rootDir": null | ||
8 | }, | 9 | }, |
9 | "include": [ | 10 | "include": [ |
10 | "src/**/*.ts" | 11 | "src/**/*.ts", |
12 | "esbuild.config.js" | ||
11 | ] | 13 | ] |
12 | } | 14 | } |
diff --git a/packages/shared/.eslintrc.cjs b/packages/shared/.eslintrc.cjs new file mode 100644 index 0000000..71d6ec4 --- /dev/null +++ b/packages/shared/.eslintrc.cjs | |||
@@ -0,0 +1,7 @@ | |||
1 | module.exports = { | ||
2 | env: { | ||
3 | // We must run in both node and browser, so we can't depend on either of them. | ||
4 | node: false, | ||
5 | browser: false, | ||
6 | }, | ||
7 | }; | ||
diff --git a/packages/shared/esbuild.config.js b/packages/shared/esbuild.config.js index 66d6658..78249ab 100644 --- a/packages/shared/esbuild.config.js +++ b/packages/shared/esbuild.config.js | |||
@@ -1,8 +1,8 @@ | |||
1 | import { chrome, node } from '../../config/buildConstants.js'; | 1 | import { chrome, node } from '../../config/buildConstants.js'; |
2 | import { getConfig } from '../../config/esbuildConfig.js'; | 2 | import fileURLToDirname from '../../config/fileURLToDirname.js'; |
3 | import { fileURLToDirname } from '../../config/utils.js'; | 3 | import getEsbuildConfig from '../../config/getEsbuildConfig.js'; |
4 | 4 | ||
5 | export default getConfig({ | 5 | export default getEsbuildConfig({ |
6 | absWorkingDir: fileURLToDirname(import.meta.url), | 6 | absWorkingDir: fileURLToDirname(import.meta.url), |
7 | entryPoints: [ | 7 | entryPoints: [ |
8 | 'src/index.ts', | 8 | 'src/index.ts', |
diff --git a/packages/shared/package.json b/packages/shared/package.json index 0c06643..d77261d 100644 --- a/packages/shared/package.json +++ b/packages/shared/package.json | |||
@@ -7,15 +7,12 @@ | |||
7 | "exports": "./dist/index.mjs", | 7 | "exports": "./dist/index.mjs", |
8 | "types": "dist/index.d.ts", | 8 | "types": "dist/index.d.ts", |
9 | "scripts": { | 9 | "scripts": { |
10 | "typecheck": "tsc" | 10 | "typecheck:workspace": "yarn g:typecheck", |
11 | "types": "yarn g:types" | ||
11 | }, | 12 | }, |
12 | "dependencies": { | 13 | "dependencies": { |
13 | "mobx": "^6.3.12", | 14 | "mobx": "^6.3.12", |
14 | "mobx-state-tree": "^5.1.0", | 15 | "mobx-state-tree": "^5.1.0", |
15 | "zod": "^3.11.6" | 16 | "zod": "^3.11.6" |
16 | }, | ||
17 | "devDependencies": { | ||
18 | "rimraf": "^3.0.2", | ||
19 | "typescript": "^4.5.4" | ||
20 | } | 17 | } |
21 | } | 18 | } |
diff --git a/packages/shared/src/contextBridge/SophieRenderer.ts b/packages/shared/src/contextBridge/SophieRenderer.ts index fc43b6e..9858aa9 100644 --- a/packages/shared/src/contextBridge/SophieRenderer.ts +++ b/packages/shared/src/contextBridge/SophieRenderer.ts | |||
@@ -18,12 +18,11 @@ | |||
18 | * SPDX-License-Identifier: AGPL-3.0-only | 18 | * SPDX-License-Identifier: AGPL-3.0-only |
19 | */ | 19 | */ |
20 | 20 | ||
21 | import { SharedStoreListener } from '../stores/SharedStore'; | ||
22 | |||
23 | import { Action } from '../schemas'; | 21 | import { Action } from '../schemas'; |
22 | import { SharedStoreListener } from '../stores/SharedStore'; | ||
24 | 23 | ||
25 | export interface SophieRenderer { | 24 | export interface SophieRenderer { |
26 | onSharedStoreChange(listener: SharedStoreListener): Promise<void>; | 25 | onSharedStoreChange(this: void, listener: SharedStoreListener): Promise<void>; |
27 | 26 | ||
28 | dispatchAction(action: Action): void; | 27 | dispatchAction(this: void, action: Action): void; |
29 | } | 28 | } |
diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 2f7146c..9828ec4 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts | |||
@@ -20,10 +20,7 @@ | |||
20 | 20 | ||
21 | export type { SophieRenderer } from './contextBridge/SophieRenderer'; | 21 | export type { SophieRenderer } from './contextBridge/SophieRenderer'; |
22 | 22 | ||
23 | export { | 23 | export { MainToRendererIpcMessage, RendererToMainIpcMessage } from './ipc'; |
24 | MainToRendererIpcMessage, | ||
25 | RendererToMainIpcMessage, | ||
26 | } from './ipc'; | ||
27 | 24 | ||
28 | export type { | 25 | export type { |
29 | Action, | 26 | Action, |
diff --git a/packages/shared/tsconfig.build.json b/packages/shared/tsconfig.build.json new file mode 100644 index 0000000..9a0c835 --- /dev/null +++ b/packages/shared/tsconfig.build.json | |||
@@ -0,0 +1,12 @@ | |||
1 | { | ||
2 | "extends": "../../config/tsconfig.base.json", | ||
3 | "compilerOptions": { | ||
4 | "composite": true, | ||
5 | "declarationDir": "dist", | ||
6 | "emitDeclarationOnly": true, | ||
7 | "rootDir": "src" | ||
8 | }, | ||
9 | "include": [ | ||
10 | "src/**/*.ts" | ||
11 | ] | ||
12 | } | ||
diff --git a/packages/shared/tsconfig.json b/packages/shared/tsconfig.json index ff5a29b..79889d2 100644 --- a/packages/shared/tsconfig.json +++ b/packages/shared/tsconfig.json | |||
@@ -1,12 +1,14 @@ | |||
1 | { | 1 | { |
2 | "extends": "../../tsconfig.json", | 2 | "extends": "./tsconfig.build.json", |
3 | "compilerOptions": { | 3 | "compilerOptions": { |
4 | "composite": true, | 4 | "composite": false, |
5 | "declarationDir": "dist", | 5 | "emitDeclarationOnly": false, |
6 | "emitDeclarationOnly": true, | 6 | "declarationDir": null, |
7 | "rootDir": "src" | 7 | "noEmit": true, |
8 | "rootDir": null | ||
8 | }, | 9 | }, |
9 | "include": [ | 10 | "include": [ |
10 | "src/**/*.ts" | 11 | "src/**/*.ts", |
12 | "esbuild.config.js" | ||
11 | ] | 13 | ] |
12 | } | 14 | } |
diff --git a/scripts/build.js b/scripts/build.js index ef2b998..1236a6c 100644 --- a/scripts/build.js +++ b/scripts/build.js | |||
@@ -1,8 +1,9 @@ | |||
1 | import { build as esbuildBuild } from 'esbuild'; | ||
2 | import { join } from 'path'; | 1 | import { join } from 'path'; |
2 | |||
3 | import { build as esbuildBuild } from 'esbuild'; | ||
3 | import { build as viteBuild } from 'vite'; | 4 | import { build as viteBuild } from 'vite'; |
4 | 5 | ||
5 | import { fileURLToDirname } from '../config/utils.js'; | 6 | import fileURLToDirname from '../config/fileURLToDirname.js'; |
6 | 7 | ||
7 | const thisDir = fileURLToDirname(import.meta.url); | 8 | const thisDir = fileURLToDirname(import.meta.url); |
8 | 9 | ||
@@ -12,6 +13,7 @@ const thisDir = fileURLToDirname(import.meta.url); | |||
12 | */ | 13 | */ |
13 | async function buildPackageEsbuild(packageName) { | 14 | async function buildPackageEsbuild(packageName) { |
14 | /** @type {{ default: import('esbuild').BuildOptions }} */ | 15 | /** @type {{ default: import('esbuild').BuildOptions }} */ |
16 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Read untyped config file. | ||
15 | const { default: config } = await import(`../packages/${packageName}/esbuild.config.js`); | 17 | const { default: config } = await import(`../packages/${packageName}/esbuild.config.js`); |
16 | return esbuildBuild(config); | 18 | return esbuildBuild(config); |
17 | } | 19 | } |
diff --git a/scripts/update-electron-vendors.js b/scripts/update-electron-vendors.js index 70d3afc..91cdb61 100644 --- a/scripts/update-electron-vendors.js +++ b/scripts/update-electron-vendors.js | |||
@@ -1,9 +1,10 @@ | |||
1 | import { execSync } from 'child_process'; | 1 | import { execSync } from 'child_process'; |
2 | import electronPath from 'electron'; | ||
3 | import { writeFile } from 'fs/promises'; | 2 | import { writeFile } from 'fs/promises'; |
4 | import { join } from 'path'; | 3 | import { join } from 'path'; |
5 | 4 | ||
6 | import { fileURLToDirname } from '../config/utils.js'; | 5 | import electronPath from 'electron'; |
6 | |||
7 | import fileURLToDirname from '../config/fileURLToDirname.js'; | ||
7 | 8 | ||
8 | const thisDir = fileURLToDirname(import.meta.url); | 9 | const thisDir = fileURLToDirname(import.meta.url); |
9 | 10 | ||
@@ -15,11 +16,12 @@ const thisDir = fileURLToDirname(import.meta.url); | |||
15 | * @returns {NodeJS.ProcessVersions} | 16 | * @returns {NodeJS.ProcessVersions} |
16 | */ | 17 | */ |
17 | function getVendors() { | 18 | function getVendors() { |
18 | const output = execSync(`${electronPath} -p "JSON.stringify(process.versions)"`, { | 19 | const output = execSync(`${electronPath.toString()} -p "JSON.stringify(process.versions)"`, { |
19 | env: { 'ELECTRON_RUN_AS_NODE': '1' }, | 20 | env: { ELECTRON_RUN_AS_NODE: '1' }, |
20 | encoding: 'utf-8', | 21 | encoding: 'utf-8', |
21 | }); | 22 | }); |
22 | 23 | ||
24 | // eslint-disable-next-line @typescript-eslint/no-unsafe-return -- Read untyped output. | ||
23 | return JSON.parse(output); | 25 | return JSON.parse(output); |
24 | } | 26 | } |
25 | 27 | ||
@@ -39,10 +41,10 @@ function updateVendors() { | |||
39 | return Promise.all([ | 41 | return Promise.all([ |
40 | writeFile( | 42 | writeFile( |
41 | join(thisDir, '../.electron-vendors.cache.json'), | 43 | join(thisDir, '../.electron-vendors.cache.json'), |
42 | JSON.stringify({ | 44 | `${JSON.stringify({ |
43 | chrome: chromeMajorVersion, | 45 | chrome: chromeMajorVersion, |
44 | node: nodeMajorVersion, | 46 | node: nodeMajorVersion, |
45 | }, null, 2) + '\n', | 47 | }, null, 2)}\n`, |
46 | ), | 48 | ), |
47 | 49 | ||
48 | writeFile(browserslistrcPath, `Chrome ${chromeMajorVersion}\n`, 'utf8'), | 50 | writeFile(browserslistrcPath, `Chrome ${chromeMajorVersion}\n`, 'utf8'), |
diff --git a/scripts/watch.js b/scripts/watch.js index a61d3c8..1345a0f 100644 --- a/scripts/watch.js +++ b/scripts/watch.js | |||
@@ -1,11 +1,12 @@ | |||
1 | import { build as esbuildBuild } from 'esbuild'; | ||
2 | import { spawn } from 'child_process'; | 1 | import { spawn } from 'child_process'; |
2 | import { join } from 'path'; | ||
3 | |||
3 | import { watch } from 'chokidar'; | 4 | import { watch } from 'chokidar'; |
4 | import electronPath from 'electron'; | 5 | import electronPath from 'electron'; |
5 | import { join } from 'path'; | 6 | import { build as esbuildBuild } from 'esbuild'; |
6 | import { createServer } from 'vite'; | 7 | import { createServer } from 'vite'; |
7 | 8 | ||
8 | import { fileURLToDirname } from '../config/utils.js'; | 9 | import fileURLToDirname from '../config/fileURLToDirname.js'; |
9 | 10 | ||
10 | /** @type {string} */ | 11 | /** @type {string} */ |
11 | const thisDir = fileURLToDirname(import.meta.url); | 12 | const thisDir = fileURLToDirname(import.meta.url); |
@@ -35,6 +36,7 @@ const stderrIgnorePatterns = [ | |||
35 | */ | 36 | */ |
36 | async function setupEsbuildWatcher(packageName, extraPaths, callback) { | 37 | async function setupEsbuildWatcher(packageName, extraPaths, callback) { |
37 | /** @type {{ default: import('esbuild').BuildOptions }} */ | 38 | /** @type {{ default: import('esbuild').BuildOptions }} */ |
39 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- Read untyped config file. | ||
38 | const { default: config } = await import(`../packages/${packageName}/esbuild.config.js`); | 40 | const { default: config } = await import(`../packages/${packageName}/esbuild.config.js`); |
39 | config.logLevel = 'info'; | 41 | config.logLevel = 'info'; |
40 | config.incremental = true; | 42 | config.incremental = true; |
@@ -45,7 +47,7 @@ async function setupEsbuildWatcher(packageName, extraPaths, callback) { | |||
45 | ...(extraPaths || []), | 47 | ...(extraPaths || []), |
46 | ]; | 48 | ]; |
47 | const watcher = watch(paths, { | 49 | const watcher = watch(paths, { |
48 | ignored: /(^|[\/\\])\.|__(tests|mocks)__|\.(spec|test)\.[jt]sx?$/, | 50 | ignored: /(^|[/\\])\.|__(tests|mocks)__|\.(spec|test)\.[jt]sx?$/, |
49 | ignoreInitial: true, | 51 | ignoreInitial: true, |
50 | persistent: true, | 52 | persistent: true, |
51 | }); | 53 | }); |
@@ -59,13 +61,26 @@ async function setupEsbuildWatcher(packageName, extraPaths, callback) { | |||
59 | callback(); | 61 | callback(); |
60 | } | 62 | } |
61 | }).catch((err) => { | 63 | }).catch((err) => { |
62 | const errCount = err.errors.length; | 64 | if (typeof err === 'object' && 'errors' in err) { |
65 | // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment -- We just checked. | ||
66 | const { errors } = err; | ||
67 | if (Array.isArray(errors)) { | ||
68 | const errCount = errors.length; | ||
69 | console.error( | ||
70 | '\ud83d\udd25', | ||
71 | errCount, | ||
72 | errCount > 1 ? 'errors' : 'error', | ||
73 | 'while rebuilding package', | ||
74 | packageName, | ||
75 | ); | ||
76 | return; | ||
77 | } | ||
78 | } | ||
63 | console.error( | 79 | console.error( |
64 | '\ud83d\udd25', | 80 | '\ud83d\udd25', |
65 | errCount, | 81 | 'error while rebuilding package', |
66 | errCount > 1 ? 'errors' : 'error', | ||
67 | 'while rebuilding package', | ||
68 | packageName, | 82 | packageName, |
83 | err, | ||
69 | ); | 84 | ); |
70 | }); | 85 | }); |
71 | }); | 86 | }); |
@@ -121,13 +136,14 @@ function setupServicePackageWatcher(packageName, sendEvent) { | |||
121 | */ | 136 | */ |
122 | function setupMainPackageWatcher(viteDevServer) { | 137 | function setupMainPackageWatcher(viteDevServer) { |
123 | // Write a value to an environment variable to pass it to the main process. | 138 | // Write a value to an environment variable to pass it to the main process. |
124 | const protocol = `http${viteDevServer.config.server.https ? 's' : ''}:`; | 139 | const { config: { server: { port, https, host } } } = viteDevServer; |
125 | const host = viteDevServer.config.server.host || 'localhost'; | 140 | const protocol = `http${https ? 's' : ''}:`; |
126 | const port = viteDevServer.config.server.port; | 141 | const hostOrDefault = typeof host === 'string' ? host : 'localhost'; |
127 | const path = '/'; | 142 | const portOrDefault = port || 3000; |
128 | process.env.VITE_DEV_SERVER_URL = `${protocol}//${host}:${port}${path}`; | 143 | process.env.VITE_DEV_SERVER_URL = `${protocol}//${hostOrDefault}:${portOrDefault}/`; |
129 | 144 | ||
130 | /** @type {import('child_process').ChildProcessByStdio<null, null, import('stream').Readable> | null} */ | 145 | /** @type {import('child_process').ChildProcessByStdio<null, null, import('stream').Readable> |
146 | | null} */ | ||
131 | let spawnProcess = null; | 147 | let spawnProcess = null; |
132 | 148 | ||
133 | return setupEsbuildWatcher( | 149 | return setupEsbuildWatcher( |
@@ -146,8 +162,8 @@ function setupMainPackageWatcher(viteDevServer) { | |||
146 | stdio: ['inherit', 'inherit', 'pipe'], | 162 | stdio: ['inherit', 'inherit', 'pipe'], |
147 | }); | 163 | }); |
148 | 164 | ||
149 | spawnProcess.stderr.on('data', (data) => { | 165 | spawnProcess.stderr.on('data', (/** @type {Buffer} */ data) => { |
150 | const stderrString = data.toString('utf-8').trimRight(); | 166 | const stderrString = data.toString('utf-8').trimEnd(); |
151 | if (!stderrIgnorePatterns.some((r) => r.test(stderrString))) { | 167 | if (!stderrIgnorePatterns.some((r) => r.test(stderrString))) { |
152 | console.error(stderrString); | 168 | console.error(stderrString); |
153 | } | 169 | } |
@@ -193,7 +209,7 @@ async function setupDevEnvironment() { | |||
193 | } | 209 | } |
194 | 210 | ||
195 | console.log('\ud83c\udf80 Sophie is starting up'); | 211 | console.log('\ud83c\udf80 Sophie is starting up'); |
196 | return setupMainPackageWatcher(viteDevServer); | 212 | await setupMainPackageWatcher(viteDevServer); |
197 | } | 213 | } |
198 | 214 | ||
199 | setupDevEnvironment().catch((err) => { | 215 | setupDevEnvironment().catch((err) => { |
diff --git a/tsconfig.json b/tsconfig.json index 255f334..627bed2 100644 --- a/tsconfig.json +++ b/tsconfig.json | |||
@@ -1,19 +1,14 @@ | |||
1 | { | 1 | { |
2 | "extends": "./config/tsconfig.base.json", | ||
2 | "compilerOptions": { | 3 | "compilerOptions": { |
3 | "module": "esnext", | 4 | "noEmit": true |
4 | "target": "esnext", | 5 | }, |
5 | "moduleResolution": "node", | 6 | "include": [ |
6 | "esModuleInterop": true, | 7 | "config/**/*.js", |
7 | "allowSyntheticDefaultImports": true, | 8 | "config/**/*.cjs", |
8 | "strict": true, | 9 | "scripts/**/*.js", |
9 | "noImplicitOverride": true, | 10 | ".electron-builder.config.cjs", |
10 | "noImplicitReturns": true, | 11 | ".eslintrc.cjs", |
11 | "exactOptionalPropertyTypes": true, | 12 | "jest.config.js" |
12 | "isolatedModules": true, | 13 | ] |
13 | "skipLibCheck": true, | ||
14 | "checkJs": true, | ||
15 | "lib": [ | ||
16 | "esnext" | ||
17 | ] | ||
18 | } | ||
19 | } | 14 | } |
@@ -420,12 +420,22 @@ __metadata: | |||
420 | languageName: node | 420 | languageName: node |
421 | linkType: hard | 421 | linkType: hard |
422 | 422 | ||
423 | "@babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7": | 423 | "@babel/runtime-corejs3@npm:^7.10.2": |
424 | version: 7.16.5 | 424 | version: 7.16.7 |
425 | resolution: "@babel/runtime@npm:7.16.5" | 425 | resolution: "@babel/runtime-corejs3@npm:7.16.7" |
426 | dependencies: | 426 | dependencies: |
427 | core-js-pure: ^3.19.0 | ||
427 | regenerator-runtime: ^0.13.4 | 428 | regenerator-runtime: ^0.13.4 |
428 | checksum: b96e67280efe581c6147b4fe984dfe08a8fbea048934a092f3cbf4dcf61725f6b221cb0c879b6e6e98671f83a104c9e8cfbd24c683e5ebcc886a731aa8984ad0 | 429 | checksum: c40cabaead64e4843a24b064cdeeabf87780bf06567146234eca94a64acb760225a9f31151eec1913c91f6f4c86afad325c5fec9262a5434e8b0a3ea905d51cf |
430 | languageName: node | ||
431 | linkType: hard | ||
432 | |||
433 | "@babel/runtime@npm:^7.10.2, @babel/runtime@npm:^7.13.10, @babel/runtime@npm:^7.16.3, @babel/runtime@npm:^7.5.5, @babel/runtime@npm:^7.7.2, @babel/runtime@npm:^7.8.7": | ||
434 | version: 7.16.7 | ||
435 | resolution: "@babel/runtime@npm:7.16.7" | ||
436 | dependencies: | ||
437 | regenerator-runtime: ^0.13.4 | ||
438 | checksum: 47912f0aaacd1cab2e2552aaf3e6eaffbcaf2d5ac9b07a89a12ac0d42029cb92c070b0d16f825e4277c4a34677c54d8ffe85e1f7c6feb57de58f700eec67ce2f | ||
429 | languageName: node | 439 | languageName: node |
430 | linkType: hard | 440 | linkType: hard |
431 | 441 | ||
@@ -1266,8 +1276,6 @@ __metadata: | |||
1266 | loglevel: ^1.8.0 | 1276 | loglevel: ^1.8.0 |
1267 | mobx: ^6.3.12 | 1277 | mobx: ^6.3.12 |
1268 | mobx-state-tree: ^5.1.0 | 1278 | mobx-state-tree: ^5.1.0 |
1269 | rimraf: ^3.0.2 | ||
1270 | typescript: ^4.5.4 | ||
1271 | languageName: unknown | 1279 | languageName: unknown |
1272 | linkType: soft | 1280 | linkType: soft |
1273 | 1281 | ||
@@ -1281,11 +1289,13 @@ __metadata: | |||
1281 | "@mui/icons-material": ^5.2.5 | 1289 | "@mui/icons-material": ^5.2.5 |
1282 | "@mui/material": ^5.2.7 | 1290 | "@mui/material": ^5.2.7 |
1283 | "@sophie/shared": "workspace:*" | 1291 | "@sophie/shared": "workspace:*" |
1284 | "@types/lodash": ^4.14.178 | 1292 | "@types/lodash-es": ^4.14.178 |
1285 | "@types/react": ^17.0.38 | 1293 | "@types/react": ^17.0.38 |
1286 | "@types/react-dom": ^17.0.11 | 1294 | "@types/react-dom": ^17.0.11 |
1287 | "@vitejs/plugin-react": ^1.1.4 | 1295 | "@vitejs/plugin-react": ^1.1.4 |
1288 | lodash: ^4.17.21 | 1296 | lodash-es: ^4.17.21 |
1297 | loglevel: ^1.8.0 | ||
1298 | loglevel-plugin-prefix: ^0.8.4 | ||
1289 | mobx: ^6.3.12 | 1299 | mobx: ^6.3.12 |
1290 | mobx-react-lite: ^3.2.3 | 1300 | mobx-react-lite: ^3.2.3 |
1291 | mobx-state-tree: ^5.1.0 | 1301 | mobx-state-tree: ^5.1.0 |
@@ -1293,8 +1303,6 @@ __metadata: | |||
1293 | react: ^17.0.2 | 1303 | react: ^17.0.2 |
1294 | react-dom: ^17.0.2 | 1304 | react-dom: ^17.0.2 |
1295 | remotedev: ^0.2.9 | 1305 | remotedev: ^0.2.9 |
1296 | rimraf: ^3.0.2 | ||
1297 | typescript: ^4.5.4 | ||
1298 | vite: ^2.7.10 | 1306 | vite: ^2.7.10 |
1299 | languageName: unknown | 1307 | languageName: unknown |
1300 | linkType: soft | 1308 | linkType: soft |
@@ -1304,8 +1312,6 @@ __metadata: | |||
1304 | resolution: "@sophie/service-inject@workspace:packages/service-inject" | 1312 | resolution: "@sophie/service-inject@workspace:packages/service-inject" |
1305 | dependencies: | 1313 | dependencies: |
1306 | "@sophie/service-shared": "workspace:*" | 1314 | "@sophie/service-shared": "workspace:*" |
1307 | rimraf: ^3.0.2 | ||
1308 | typescript: ^4.5.4 | ||
1309 | languageName: unknown | 1315 | languageName: unknown |
1310 | linkType: soft | 1316 | linkType: soft |
1311 | 1317 | ||
@@ -1315,8 +1321,8 @@ __metadata: | |||
1315 | dependencies: | 1321 | dependencies: |
1316 | "@sophie/service-shared": "workspace:*" | 1322 | "@sophie/service-shared": "workspace:*" |
1317 | electron: 16.0.6 | 1323 | electron: 16.0.6 |
1318 | rimraf: ^3.0.2 | 1324 | loglevel: ^1.8.0 |
1319 | typescript: ^4.5.4 | 1325 | loglevel-plugin-prefix: ^0.8.4 |
1320 | languageName: unknown | 1326 | languageName: unknown |
1321 | linkType: soft | 1327 | linkType: soft |
1322 | 1328 | ||
@@ -1324,8 +1330,6 @@ __metadata: | |||
1324 | version: 0.0.0-use.local | 1330 | version: 0.0.0-use.local |
1325 | resolution: "@sophie/service-shared@workspace:packages/service-shared" | 1331 | resolution: "@sophie/service-shared@workspace:packages/service-shared" |
1326 | dependencies: | 1332 | dependencies: |
1327 | rimraf: ^3.0.2 | ||
1328 | typescript: ^4.5.4 | ||
1329 | zod: ^3.11.6 | 1333 | zod: ^3.11.6 |
1330 | languageName: unknown | 1334 | languageName: unknown |
1331 | linkType: soft | 1335 | linkType: soft |
@@ -1336,8 +1340,6 @@ __metadata: | |||
1336 | dependencies: | 1340 | dependencies: |
1337 | mobx: ^6.3.12 | 1341 | mobx: ^6.3.12 |
1338 | mobx-state-tree: ^5.1.0 | 1342 | mobx-state-tree: ^5.1.0 |
1339 | rimraf: ^3.0.2 | ||
1340 | typescript: ^4.5.4 | ||
1341 | zod: ^3.11.6 | 1343 | zod: ^3.11.6 |
1342 | languageName: unknown | 1344 | languageName: unknown |
1343 | linkType: soft | 1345 | linkType: soft |
@@ -1508,7 +1510,7 @@ __metadata: | |||
1508 | languageName: node | 1510 | languageName: node |
1509 | linkType: hard | 1511 | linkType: hard |
1510 | 1512 | ||
1511 | "@types/lodash-es@npm:^4.17.5": | 1513 | "@types/lodash-es@npm:^4.14.178, @types/lodash-es@npm:^4.17.5": |
1512 | version: 4.17.5 | 1514 | version: 4.17.5 |
1513 | resolution: "@types/lodash-es@npm:4.17.5" | 1515 | resolution: "@types/lodash-es@npm:4.17.5" |
1514 | dependencies: | 1516 | dependencies: |
@@ -1517,7 +1519,7 @@ __metadata: | |||
1517 | languageName: node | 1519 | languageName: node |
1518 | linkType: hard | 1520 | linkType: hard |
1519 | 1521 | ||
1520 | "@types/lodash@npm:*, @types/lodash@npm:^4.14.178": | 1522 | "@types/lodash@npm:*": |
1521 | version: 4.14.178 | 1523 | version: 4.14.178 |
1522 | resolution: "@types/lodash@npm:4.14.178" | 1524 | resolution: "@types/lodash@npm:4.14.178" |
1523 | checksum: a69a04a60bfc5257c3130a554b4efa0c383f0141b7b3db8ab7cf07ad2a46ea085fce66d0242da41da7e5647b133d5dfb2c15add9cbed8d7fef955e4a1e5b3128 | 1525 | checksum: a69a04a60bfc5257c3130a554b4efa0c383f0141b7b3db8ab7cf07ad2a46ea085fce66d0242da41da7e5647b133d5dfb2c15add9cbed8d7fef955e4a1e5b3128 |
@@ -2058,6 +2060,16 @@ __metadata: | |||
2058 | languageName: node | 2060 | languageName: node |
2059 | linkType: hard | 2061 | linkType: hard |
2060 | 2062 | ||
2063 | "aria-query@npm:^4.2.2": | ||
2064 | version: 4.2.2 | ||
2065 | resolution: "aria-query@npm:4.2.2" | ||
2066 | dependencies: | ||
2067 | "@babel/runtime": ^7.10.2 | ||
2068 | "@babel/runtime-corejs3": ^7.10.2 | ||
2069 | checksum: 38401a9a400f26f3dcc24b84997461a16b32869a9893d323602bed8da40a8bcc0243b8d2880e942249a1496cea7a7de769e93d21c0baa439f01e1ee936fed665 | ||
2070 | languageName: node | ||
2071 | linkType: hard | ||
2072 | |||
2061 | "array-includes@npm:^3.1.3, array-includes@npm:^3.1.4": | 2073 | "array-includes@npm:^3.1.3, array-includes@npm:^3.1.4": |
2062 | version: 3.1.4 | 2074 | version: 3.1.4 |
2063 | resolution: "array-includes@npm:3.1.4" | 2075 | resolution: "array-includes@npm:3.1.4" |
@@ -2125,6 +2137,13 @@ __metadata: | |||
2125 | languageName: node | 2137 | languageName: node |
2126 | linkType: hard | 2138 | linkType: hard |
2127 | 2139 | ||
2140 | "ast-types-flow@npm:^0.0.7": | ||
2141 | version: 0.0.7 | ||
2142 | resolution: "ast-types-flow@npm:0.0.7" | ||
2143 | checksum: a26dcc2182ffee111cad7c471759b0bda22d3b7ebacf27c348b22c55f16896b18ab0a4d03b85b4020dce7f3e634b8f00b593888f622915096ea1927fa51866c4 | ||
2144 | languageName: node | ||
2145 | linkType: hard | ||
2146 | |||
2128 | "astral-regex@npm:^2.0.0": | 2147 | "astral-regex@npm:^2.0.0": |
2129 | version: 2.0.0 | 2148 | version: 2.0.0 |
2130 | resolution: "astral-regex@npm:2.0.0" | 2149 | resolution: "astral-regex@npm:2.0.0" |
@@ -2167,6 +2186,20 @@ __metadata: | |||
2167 | languageName: node | 2186 | languageName: node |
2168 | linkType: hard | 2187 | linkType: hard |
2169 | 2188 | ||
2189 | "axe-core@npm:^4.3.5": | ||
2190 | version: 4.3.5 | ||
2191 | resolution: "axe-core@npm:4.3.5" | ||
2192 | checksum: 973c6a80f0aaa663820b209d4202de7a0c240a2dea2f3cff168b09c0f221b27179b1f0988f00ad11ed63cbc50535920f8ca779de1c60dc82090ab2d275f71fdd | ||
2193 | languageName: node | ||
2194 | linkType: hard | ||
2195 | |||
2196 | "axobject-query@npm:^2.2.0": | ||
2197 | version: 2.2.0 | ||
2198 | resolution: "axobject-query@npm:2.2.0" | ||
2199 | checksum: 96b8c7d807ca525f41ad9b286186e2089b561ba63a6d36c3e7d73dc08150714660995c7ad19cda05784458446a0793b45246db45894631e13853f48c1aa3117f | ||
2200 | languageName: node | ||
2201 | linkType: hard | ||
2202 | |||
2170 | "babel-jest@npm:^27.4.6": | 2203 | "babel-jest@npm:^27.4.6": |
2171 | version: 27.4.6 | 2204 | version: 27.4.6 |
2172 | resolution: "babel-jest@npm:27.4.6" | 2205 | resolution: "babel-jest@npm:27.4.6" |
@@ -2855,6 +2888,13 @@ __metadata: | |||
2855 | languageName: node | 2888 | languageName: node |
2856 | linkType: hard | 2889 | linkType: hard |
2857 | 2890 | ||
2891 | "core-js-pure@npm:^3.19.0": | ||
2892 | version: 3.20.2 | ||
2893 | resolution: "core-js-pure@npm:3.20.2" | ||
2894 | checksum: d6b3f6782e3f2fc27eb2335917d5c5d0e7621e424c25da67429e9b48b7708b76fdc4a178b245421eeb8342c0ea9b0ca636ece002db3d0e68246a9d395d461ca7 | ||
2895 | languageName: node | ||
2896 | linkType: hard | ||
2897 | |||
2858 | "core-util-is@npm:1.0.2": | 2898 | "core-util-is@npm:1.0.2": |
2859 | version: 1.0.2 | 2899 | version: 1.0.2 |
2860 | resolution: "core-util-is@npm:1.0.2" | 2900 | resolution: "core-util-is@npm:1.0.2" |
@@ -2958,6 +2998,13 @@ __metadata: | |||
2958 | languageName: node | 2998 | languageName: node |
2959 | linkType: hard | 2999 | linkType: hard |
2960 | 3000 | ||
3001 | "damerau-levenshtein@npm:^1.0.7": | ||
3002 | version: 1.0.7 | ||
3003 | resolution: "damerau-levenshtein@npm:1.0.7" | ||
3004 | checksum: ec8161cb381523e0db9b5c9b64863736da3197808b6fdc4a3a2ca764c0b4357e9232a4c5592220fb18755a91240b8fee7b13ab1b269fbbdc5f68c36f0053aceb | ||
3005 | languageName: node | ||
3006 | linkType: hard | ||
3007 | |||
2961 | "data-urls@npm:^2.0.0": | 3008 | "data-urls@npm:^2.0.0": |
2962 | version: 2.0.0 | 3009 | version: 2.0.0 |
2963 | resolution: "data-urls@npm:2.0.0" | 3010 | resolution: "data-urls@npm:2.0.0" |
@@ -3373,6 +3420,13 @@ __metadata: | |||
3373 | languageName: node | 3420 | languageName: node |
3374 | linkType: hard | 3421 | linkType: hard |
3375 | 3422 | ||
3423 | "emoji-regex@npm:^9.2.2": | ||
3424 | version: 9.2.2 | ||
3425 | resolution: "emoji-regex@npm:9.2.2" | ||
3426 | checksum: 8487182da74aabd810ac6d6f1994111dfc0e331b01271ae01ec1eb0ad7b5ecc2bbbbd2f053c05cb55a1ac30449527d819bbfbf0e3de1023db308cbcb47f86601 | ||
3427 | languageName: node | ||
3428 | linkType: hard | ||
3429 | |||
3376 | "encodeurl@npm:^1.0.2": | 3430 | "encodeurl@npm:^1.0.2": |
3377 | version: 1.0.2 | 3431 | version: 1.0.2 |
3378 | resolution: "encodeurl@npm:1.0.2" | 3432 | resolution: "encodeurl@npm:1.0.2" |
@@ -3929,6 +3983,35 @@ __metadata: | |||
3929 | languageName: node | 3983 | languageName: node |
3930 | linkType: hard | 3984 | linkType: hard |
3931 | 3985 | ||
3986 | "eslint-config-airbnb@npm:^19.0.4": | ||
3987 | version: 19.0.4 | ||
3988 | resolution: "eslint-config-airbnb@npm:19.0.4" | ||
3989 | dependencies: | ||
3990 | eslint-config-airbnb-base: ^15.0.0 | ||
3991 | object.assign: ^4.1.2 | ||
3992 | object.entries: ^1.1.5 | ||
3993 | peerDependencies: | ||
3994 | eslint: ^7.32.0 || ^8.2.0 | ||
3995 | eslint-plugin-import: ^2.25.3 | ||
3996 | eslint-plugin-jsx-a11y: ^6.5.1 | ||
3997 | eslint-plugin-react: ^7.28.0 | ||
3998 | eslint-plugin-react-hooks: ^4.3.0 | ||
3999 | checksum: 253178689c3c80eef2567e3aaf0612e18973bc9cf51d9be36074b5dd58210e8b6942200a424bcccbb81ac884e41303479ab09f251a2a97addc2de61efdc9576c | ||
4000 | languageName: node | ||
4001 | linkType: hard | ||
4002 | |||
4003 | "eslint-formatter-gitlab@npm:^3.0.0": | ||
4004 | version: 3.0.0 | ||
4005 | resolution: "eslint-formatter-gitlab@npm:3.0.0" | ||
4006 | dependencies: | ||
4007 | chalk: ^4.0.0 | ||
4008 | js-yaml: ^4.0.0 | ||
4009 | peerDependencies: | ||
4010 | eslint: ^5 || ^6 || ^7 || ^8 | ||
4011 | checksum: 7730a003e5e9b2bde7a8cc473d8b377ac198be33a9e0f1dbc7e5ddf489232dc683b8aedd2726c0539e0d2e73b9769b2fcaf089ad90b75fc8564a0b4a9511d041 | ||
4012 | languageName: node | ||
4013 | linkType: hard | ||
4014 | |||
3932 | "eslint-import-resolver-node@npm:^0.3.6": | 4015 | "eslint-import-resolver-node@npm:^0.3.6": |
3933 | version: 0.3.6 | 4016 | version: 0.3.6 |
3934 | resolution: "eslint-import-resolver-node@npm:0.3.6" | 4017 | resolution: "eslint-import-resolver-node@npm:0.3.6" |
@@ -3939,6 +4022,22 @@ __metadata: | |||
3939 | languageName: node | 4022 | languageName: node |
3940 | linkType: hard | 4023 | linkType: hard |
3941 | 4024 | ||
4025 | "eslint-import-resolver-typescript@npm:^2.5.0": | ||
4026 | version: 2.5.0 | ||
4027 | resolution: "eslint-import-resolver-typescript@npm:2.5.0" | ||
4028 | dependencies: | ||
4029 | debug: ^4.3.1 | ||
4030 | glob: ^7.1.7 | ||
4031 | is-glob: ^4.0.1 | ||
4032 | resolve: ^1.20.0 | ||
4033 | tsconfig-paths: ^3.9.0 | ||
4034 | peerDependencies: | ||
4035 | eslint: "*" | ||
4036 | eslint-plugin-import: "*" | ||
4037 | checksum: e507a0cb46a05f136b1416664c7cbe1b1178001417421ce5621f147e88c8973b5c9ee1554dbf0b79ae93f760d69f2796e1a880d562356a080e9e4ac1058206a3 | ||
4038 | languageName: node | ||
4039 | linkType: hard | ||
4040 | |||
3942 | "eslint-module-utils@npm:^2.7.2": | 4041 | "eslint-module-utils@npm:^2.7.2": |
3943 | version: 2.7.2 | 4042 | version: 2.7.2 |
3944 | resolution: "eslint-module-utils@npm:2.7.2" | 4043 | resolution: "eslint-module-utils@npm:2.7.2" |
@@ -3972,6 +4071,37 @@ __metadata: | |||
3972 | languageName: node | 4071 | languageName: node |
3973 | linkType: hard | 4072 | linkType: hard |
3974 | 4073 | ||
4074 | "eslint-plugin-jsx-a11y@npm:^6.5.1": | ||
4075 | version: 6.5.1 | ||
4076 | resolution: "eslint-plugin-jsx-a11y@npm:6.5.1" | ||
4077 | dependencies: | ||
4078 | "@babel/runtime": ^7.16.3 | ||
4079 | aria-query: ^4.2.2 | ||
4080 | array-includes: ^3.1.4 | ||
4081 | ast-types-flow: ^0.0.7 | ||
4082 | axe-core: ^4.3.5 | ||
4083 | axobject-query: ^2.2.0 | ||
4084 | damerau-levenshtein: ^1.0.7 | ||
4085 | emoji-regex: ^9.2.2 | ||
4086 | has: ^1.0.3 | ||
4087 | jsx-ast-utils: ^3.2.1 | ||
4088 | language-tags: ^1.0.5 | ||
4089 | minimatch: ^3.0.4 | ||
4090 | peerDependencies: | ||
4091 | eslint: ^3 || ^4 || ^5 || ^6 || ^7 || ^8 | ||
4092 | checksum: 311ab993ed982d0cc7cb0ba02fbc4b36c4a94e9434f31e97f13c4d67e8ecb8aec36baecfd759ff70498846e7e11d7a197eb04c39ad64934baf3354712fd0bc9d | ||
4093 | languageName: node | ||
4094 | linkType: hard | ||
4095 | |||
4096 | "eslint-plugin-react-hooks@npm:^4.3.0": | ||
4097 | version: 4.3.0 | ||
4098 | resolution: "eslint-plugin-react-hooks@npm:4.3.0" | ||
4099 | peerDependencies: | ||
4100 | eslint: ^3.0.0 || ^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0-0 | ||
4101 | checksum: 0ba1566ba0780bbc75a5921f49188edf232db2085ab32c8d3889592f0db9d6fadc97fcf639775e0101dec6b5409ca3c803ec44213b90c8bacaf0bdf921871c2e | ||
4102 | languageName: node | ||
4103 | linkType: hard | ||
4104 | |||
3975 | "eslint-plugin-react@npm:^7.28.0": | 4105 | "eslint-plugin-react@npm:^7.28.0": |
3976 | version: 7.28.0 | 4106 | version: 7.28.0 |
3977 | resolution: "eslint-plugin-react@npm:7.28.0" | 4107 | resolution: "eslint-plugin-react@npm:7.28.0" |
@@ -4558,7 +4688,7 @@ __metadata: | |||
4558 | languageName: node | 4688 | languageName: node |
4559 | linkType: hard | 4689 | linkType: hard |
4560 | 4690 | ||
4561 | "glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6": | 4691 | "glob@npm:^7.1.1, glob@npm:^7.1.2, glob@npm:^7.1.3, glob@npm:^7.1.4, glob@npm:^7.1.6, glob@npm:^7.1.7": |
4562 | version: 7.2.0 | 4692 | version: 7.2.0 |
4563 | resolution: "glob@npm:7.2.0" | 4693 | resolution: "glob@npm:7.2.0" |
4564 | dependencies: | 4694 | dependencies: |
@@ -5857,7 +5987,7 @@ __metadata: | |||
5857 | languageName: node | 5987 | languageName: node |
5858 | linkType: hard | 5988 | linkType: hard |
5859 | 5989 | ||
5860 | "js-yaml@npm:^4.1.0": | 5990 | "js-yaml@npm:^4.0.0, js-yaml@npm:^4.1.0": |
5861 | version: 4.1.0 | 5991 | version: 4.1.0 |
5862 | resolution: "js-yaml@npm:4.1.0" | 5992 | resolution: "js-yaml@npm:4.1.0" |
5863 | dependencies: | 5993 | dependencies: |
@@ -6053,7 +6183,7 @@ __metadata: | |||
6053 | languageName: node | 6183 | languageName: node |
6054 | linkType: hard | 6184 | linkType: hard |
6055 | 6185 | ||
6056 | "jsx-ast-utils@npm:^2.4.1 || ^3.0.0": | 6186 | "jsx-ast-utils@npm:^2.4.1 || ^3.0.0, jsx-ast-utils@npm:^3.2.1": |
6057 | version: 3.2.1 | 6187 | version: 3.2.1 |
6058 | resolution: "jsx-ast-utils@npm:3.2.1" | 6188 | resolution: "jsx-ast-utils@npm:3.2.1" |
6059 | dependencies: | 6189 | dependencies: |
@@ -6091,6 +6221,22 @@ __metadata: | |||
6091 | languageName: node | 6221 | languageName: node |
6092 | linkType: hard | 6222 | linkType: hard |
6093 | 6223 | ||
6224 | "language-subtag-registry@npm:~0.3.2": | ||
6225 | version: 0.3.21 | ||
6226 | resolution: "language-subtag-registry@npm:0.3.21" | ||
6227 | checksum: 5f794525a5bfcefeea155a681af1c03365b60e115b688952a53c6e0b9532b09163f57f1fcb69d6150e0e805ec0350644a4cb35da98f4902562915be9f89572a1 | ||
6228 | languageName: node | ||
6229 | linkType: hard | ||
6230 | |||
6231 | "language-tags@npm:^1.0.5": | ||
6232 | version: 1.0.5 | ||
6233 | resolution: "language-tags@npm:1.0.5" | ||
6234 | dependencies: | ||
6235 | language-subtag-registry: ~0.3.2 | ||
6236 | checksum: c81b5d8b9f5f9cfd06ee71ada6ddfe1cf83044dd5eeefcd1e420ad491944da8957688db4a0a9bc562df4afdc2783425cbbdfd152c01d93179cf86888903123cf | ||
6237 | languageName: node | ||
6238 | linkType: hard | ||
6239 | |||
6094 | "latest-version@npm:^5.1.0": | 6240 | "latest-version@npm:^5.1.0": |
6095 | version: 5.1.0 | 6241 | version: 5.1.0 |
6096 | resolution: "latest-version@npm:5.1.0" | 6242 | resolution: "latest-version@npm:5.1.0" |
@@ -6190,7 +6336,7 @@ __metadata: | |||
6190 | languageName: node | 6336 | languageName: node |
6191 | linkType: hard | 6337 | linkType: hard |
6192 | 6338 | ||
6193 | "lodash@npm:^4.17.10, lodash@npm:^4.17.15, lodash@npm:^4.17.21, lodash@npm:^4.7.0": | 6339 | "lodash@npm:^4.17.10, lodash@npm:^4.17.15, lodash@npm:^4.7.0": |
6194 | version: 4.17.21 | 6340 | version: 4.17.21 |
6195 | resolution: "lodash@npm:4.17.21" | 6341 | resolution: "lodash@npm:4.17.21" |
6196 | checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 | 6342 | checksum: eb835a2e51d381e561e508ce932ea50a8e5a68f4ebdd771ea240d3048244a8d13658acbd502cd4829768c56f2e16bdd4340b9ea141297d472517b83868e677f7 |
@@ -7789,9 +7935,15 @@ __metadata: | |||
7789 | electron-builder: ^22.14.12 | 7935 | electron-builder: ^22.14.12 |
7790 | esbuild: ^0.14.11 | 7936 | esbuild: ^0.14.11 |
7791 | eslint: ^8.6.0 | 7937 | eslint: ^8.6.0 |
7938 | eslint-config-airbnb: ^19.0.4 | ||
7939 | eslint-config-airbnb-base: ^15.0.0 | ||
7792 | eslint-config-airbnb-typescript: ^16.1.0 | 7940 | eslint-config-airbnb-typescript: ^16.1.0 |
7941 | eslint-formatter-gitlab: ^3.0.0 | ||
7942 | eslint-import-resolver-typescript: ^2.5.0 | ||
7793 | eslint-plugin-import: ^2.25.4 | 7943 | eslint-plugin-import: ^2.25.4 |
7944 | eslint-plugin-jsx-a11y: ^6.5.1 | ||
7794 | eslint-plugin-react: ^7.28.0 | 7945 | eslint-plugin-react: ^7.28.0 |
7946 | eslint-plugin-react-hooks: ^4.3.0 | ||
7795 | git-repo-info: ^2.1.1 | 7947 | git-repo-info: ^2.1.1 |
7796 | jest: ^27.4.7 | 7948 | jest: ^27.4.7 |
7797 | preload: ^0.1.0 | 7949 | preload: ^0.1.0 |
@@ -8224,7 +8376,7 @@ __metadata: | |||
8224 | languageName: node | 8376 | languageName: node |
8225 | linkType: hard | 8377 | linkType: hard |
8226 | 8378 | ||
8227 | "tsconfig-paths@npm:^3.12.0": | 8379 | "tsconfig-paths@npm:^3.12.0, tsconfig-paths@npm:^3.9.0": |
8228 | version: 3.12.0 | 8380 | version: 3.12.0 |
8229 | resolution: "tsconfig-paths@npm:3.12.0" | 8381 | resolution: "tsconfig-paths@npm:3.12.0" |
8230 | dependencies: | 8382 | dependencies: |