jupyterlab_code_formatter 2.2.1 → 3.0.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -1,31 +1,36 @@
1
1
  ![](docs/logo.png)
2
2
 
3
- *A JupyterLab plugin to facilitate invocation of code formatters.*
3
+ [![Extension status](https://img.shields.io/badge/status-ready-success 'ready to be used')](https://jupyterlab-contrib.github.io/)
4
+ [![GitHub Action Status](https://github.com/jupyterlab-contrib/jupyterlab_code_formatter/actions/workflows/build.yml/badge.svg)](https://github.com/jupyterlab-contrib/jupyterlab_code_formatter/actions/workflows/build.yml)
5
+ [![Binder](https://mybinder.org/badge_logo.svg)](https://mybinder.org/v2/gh/jupyterlab-contrib/jupyterlab_code_formatter/master?urlpath=lab)
6
+ [![pypi-version](https://img.shields.io/pypi/v/jupyterlab-code-formatter.svg)](https://python.org/pypi/jupyterlab-code-formatter)
4
7
 
5
- PSA: I can only dedicate a few hours per week for this plugin, bear with me if your request/issue is taking a while to be fixed.
8
+ _A JupyterLab plugin to facilitate invocation of code formatters._
6
9
 
7
- ----
10
+ ---
8
11
 
9
12
  Documentation: [Hosted on ReadTheDocs](https://jupyterlab-code-formatter.readthedocs.io/)
10
13
 
11
- ----
14
+ ---
12
15
 
13
16
  ## Demo
14
17
 
15
18
  ![](docs/_static/format-all.gif)
16
19
 
17
- ----
20
+ ---
18
21
 
19
22
  ## Quick Start
20
23
 
21
24
  I recommend you going to the [documentation site](https://jupyterlab-code-formatter.readthedocs.io/#quick-start), but this should work too.
22
25
 
23
26
  1. **Install the package**
27
+
24
28
  ```bash
25
29
  pip install jupyterlab-code-formatter
26
30
  ```
27
31
 
28
32
  2. **Install some supported formatters** (isort+black are default for Python)
33
+
29
34
  ```bash
30
35
  # NOTE: Install black and isort,
31
36
  # JL code formatter is configured to invoke isort and black by default
@@ -40,25 +45,30 @@ This plugin includes a server plugin, restart JupyterLab if you have followed th
40
45
 
41
46
  To configure which/how formatters are invoked, see [configuration](https://jupyterlab-code-formatter.readthedocs.io/configuration.html).
42
47
 
43
- ----
48
+ ---
49
+
50
+ ## Getting help
51
+
52
+ If you don't use Discord then feel free to open a [GitHub issue](https://github.com/jupyterlab-contrib/jupyterlab_code_formatter/issues), do note I am a bit slower in responding in GitHub.
53
+
54
+ ---
44
55
 
45
56
  ## Your Support
46
57
 
47
- I could really use your support in giving me a star on GitHub, recommending features, fixing bugs or maybe even providing monetary support!
58
+ I could really use your support in giving me a star on GitHub, recommending features or fixing bugs.
48
59
 
49
- - [Recommending features via GitHub Issues](https://github.com/ryantam626/jupyterlab_code_formatter/issues)
50
- - [Sumitting your PR on GitHub](https://github.com/ryantam626/jupyterlab_code_formatter/pulls)
51
- - [Buy me a coffee](https://www.buymeacoffee.com/ryantam626)
52
- - [Donating Via Solana](https://solana.com/): 6K7aK5RpskJkhEkwZi1ZQr68LhaVdfnTfWjZEQV3VbbD
60
+ - [Recommending features via GitHub Issues](https://github.com/jupyterlab-contrib/jupyterlab_code_formatter/issues)
61
+ - [Submitting your PR on GitHub](https://github.com/jupyterlab-contrib/jupyterlab_code_formatter/pulls)
53
62
 
54
- ----
63
+ ---
55
64
 
56
65
  ## Contributors
57
66
 
67
+ This extension was originally developed and maintained by [@ryantam626](https://github.com/ryantam626).
58
68
  Massive thanks to the below list of people who made past contributions to the project!
59
69
 
60
- <a href="https://github.com/ryantam626/jupyterlab_code_formatter/graphs/contributors">
61
- <img src="https://contrib.rocks/image?repo=ryantam626/jupyterlab_code_formatter" />
70
+ <a href="https://github.com/jupyterlab-contrib/jupyterlab_code_formatter/graphs/contributors">
71
+ <img src="https://contrib.rocks/image?repo=jupyterlab-contrib/jupyterlab_code_formatter" />
62
72
  </a>
63
73
 
64
74
  ## License
@@ -2,6 +2,9 @@ import { INotebookTracker, Notebook } from '@jupyterlab/notebook';
2
2
  import JupyterlabCodeFormatterClient from './client';
3
3
  import { IEditorTracker } from '@jupyterlab/fileeditor';
4
4
  import { Widget } from '@lumino/widgets';
5
+ type Context = {
6
+ saving: boolean;
7
+ };
5
8
  declare class JupyterlabCodeFormatter {
6
9
  working: boolean;
7
10
  protected client: JupyterlabCodeFormatterClient;
@@ -13,7 +16,7 @@ export declare class JupyterlabNotebookCodeFormatter extends JupyterlabCodeForma
13
16
  constructor(client: JupyterlabCodeFormatterClient, notebookTracker: INotebookTracker);
14
17
  formatAction(config: any, formatter?: string): Promise<void>;
15
18
  formatSelectedCodeCells(config: any, formatter?: string, notebook?: Notebook): Promise<void>;
16
- formatAllCodeCells(config: any, formatter?: string, notebook?: Notebook): Promise<void>;
19
+ formatAllCodeCells(config: any, context: Context, formatter?: string, notebook?: Notebook): Promise<void>;
17
20
  private getCodeCells;
18
21
  private getNotebookType;
19
22
  private getDefaultFormatters;
@@ -25,7 +28,12 @@ export declare class JupyterlabNotebookCodeFormatter extends JupyterlabCodeForma
25
28
  export declare class JupyterlabFileEditorCodeFormatter extends JupyterlabCodeFormatter {
26
29
  protected editorTracker: IEditorTracker;
27
30
  constructor(client: JupyterlabCodeFormatterClient, editorTracker: IEditorTracker);
28
- formatAction(config: any, formatter: string): void;
31
+ formatAction(config: any, formatter: string): Promise<void>;
32
+ formatEditor(config: any, context: Context, formatter?: string): Promise<void>;
33
+ private getEditorType;
34
+ private getDefaultFormatters;
35
+ private getFormattersToUse;
36
+ private applyFormatters;
29
37
  applicable(formatter: string, currentWidget: Widget): boolean | null;
30
38
  }
31
39
  export {};
package/lib/formatter.js CHANGED
@@ -1,4 +1,4 @@
1
- import { showErrorMessage } from '@jupyterlab/apputils';
1
+ import { showErrorMessage, Dialog, showDialog } from '@jupyterlab/apputils';
2
2
  class JupyterlabCodeFormatter {
3
3
  constructor(client) {
4
4
  this.working = false;
@@ -21,13 +21,13 @@ export class JupyterlabNotebookCodeFormatter extends JupyterlabCodeFormatter {
21
21
  this.notebookTracker = notebookTracker;
22
22
  }
23
23
  async formatAction(config, formatter) {
24
- return this.formatCells(true, config, formatter);
24
+ return this.formatCells(true, config, { saving: false }, formatter);
25
25
  }
26
26
  async formatSelectedCodeCells(config, formatter, notebook) {
27
- return this.formatCells(true, config, formatter, notebook);
27
+ return this.formatCells(true, config, { saving: false }, formatter, notebook);
28
28
  }
29
- async formatAllCodeCells(config, formatter, notebook) {
30
- return this.formatCells(false, config, formatter, notebook);
29
+ async formatAllCodeCells(config, context, formatter, notebook) {
30
+ return this.formatCells(false, config, context, formatter, notebook);
31
31
  }
32
32
  getCodeCells(selectedOnly = true, notebook) {
33
33
  if (!this.notebookTracker.currentWidget) {
@@ -45,25 +45,39 @@ export class JupyterlabNotebookCodeFormatter extends JupyterlabCodeFormatter {
45
45
  return codeCells;
46
46
  }
47
47
  getNotebookType() {
48
+ var _a, _b, _c, _d, _e;
49
+ // If there is no current notebook, there is nothing to do
48
50
  if (!this.notebookTracker.currentWidget) {
49
51
  return null;
50
52
  }
51
- const metadata = this.notebookTracker.currentWidget.content.model.sharedModel.metadata;
52
- ;
53
- if (!metadata) {
54
- return null;
55
- }
56
- // prefer kernelspec language
57
- // @ts-ignore
58
- if (metadata.kernelspec && metadata.kernelspec.language) {
59
- // @ts-ignore
60
- return metadata.kernelspec.language.toLowerCase();
53
+ // first, check the notebook's metadata for language info
54
+ const metadata = (_b = (_a = this.notebookTracker.currentWidget.content.model) === null || _a === void 0 ? void 0 : _a.sharedModel) === null || _b === void 0 ? void 0 : _b.metadata;
55
+ if (metadata) {
56
+ // prefer kernelspec language
57
+ if (metadata.kernelspec &&
58
+ metadata.kernelspec.language &&
59
+ typeof metadata.kernelspec.language === 'string') {
60
+ return metadata.kernelspec.language.toLowerCase();
61
+ }
62
+ // otherwise, check language info code mirror mode
63
+ if (metadata.language_info && metadata.language_info.codemirror_mode) {
64
+ const mode = metadata.language_info.codemirror_mode;
65
+ if (typeof mode === 'string') {
66
+ return mode.toLowerCase();
67
+ }
68
+ else if (typeof mode.name === 'string') {
69
+ return mode.name.toLowerCase();
70
+ }
71
+ }
61
72
  }
62
- // otherwise, check language info code mirror mode
63
- // @ts-ignore
64
- if (metadata.language_info && metadata.language_info.codemirror_mode) {
65
- // @ts-ignore
66
- return metadata.language_info.codemirror_mode.name.toLowerCase();
73
+ // in the absence of metadata, look in the current session's kernel spec
74
+ const sessionContext = this.notebookTracker.currentWidget.sessionContext;
75
+ const kernelName = (_d = (_c = sessionContext === null || sessionContext === void 0 ? void 0 : sessionContext.session) === null || _c === void 0 ? void 0 : _c.kernel) === null || _d === void 0 ? void 0 : _d.name;
76
+ if (kernelName) {
77
+ const specs = (_e = sessionContext.specsManager.specs) === null || _e === void 0 ? void 0 : _e.kernelspecs;
78
+ if (specs && kernelName in specs) {
79
+ return specs[kernelName].language;
80
+ }
67
81
  }
68
82
  return null;
69
83
  }
@@ -88,15 +102,18 @@ export class JupyterlabNotebookCodeFormatter extends JupyterlabCodeFormatter {
88
102
  }
89
103
  return formattersToUse;
90
104
  }
91
- async applyFormatters(selectedCells, formattersToUse, config) {
92
- var _a;
105
+ async applyFormatters(selectedCells, formattersToUse, config, context) {
106
+ var _a, _b;
93
107
  for (const formatterToUse of formattersToUse) {
94
108
  if (formatterToUse === 'noop' || formatterToUse === 'skip') {
95
109
  continue;
96
110
  }
97
111
  const currentTexts = selectedCells.map(cell => cell.model.sharedModel.source);
98
112
  const formattedTexts = await this.formatCode(currentTexts, formatterToUse, config[formatterToUse], true, config.cacheFormatters);
99
- const showErrors = !((_a = config.suppressFormatterErrors) !== null && _a !== void 0 ? _a : false);
113
+ console.log(config.suppressFormatterErrorsIFFAutoFormatOnSave, context.saving);
114
+ const showErrors = !((_a = config.suppressFormatterErrors) !== null && _a !== void 0 ? _a : false) &&
115
+ !(((_b = config.suppressFormatterErrorsIFFAutoFormatOnSave) !== null && _b !== void 0 ? _b : false) &&
116
+ context.saving);
100
117
  for (let i = 0; i < selectedCells.length; ++i) {
101
118
  const cell = selectedCells[i];
102
119
  const currentText = currentTexts[i];
@@ -105,7 +122,21 @@ export class JupyterlabNotebookCodeFormatter extends JupyterlabCodeFormatter {
105
122
  if (cellValueHasNotChanged) {
106
123
  if (formattedText.error) {
107
124
  if (showErrors) {
108
- await showErrorMessage('Jupyterlab Code Formatter Error', formattedText.error);
125
+ const result = await showDialog({
126
+ title: 'Jupyterlab Code Formatter Error',
127
+ body: formattedText.error,
128
+ buttons: [
129
+ Dialog.createButton({
130
+ label: 'Go to cell',
131
+ actions: ['revealError']
132
+ }),
133
+ Dialog.okButton({ label: 'Dismiss' })
134
+ ]
135
+ });
136
+ if (result.button.actions.indexOf('revealError') !== -1) {
137
+ this.notebookTracker.currentWidget.content.scrollToCell(cell);
138
+ break;
139
+ }
109
140
  }
110
141
  }
111
142
  else {
@@ -120,7 +151,7 @@ export class JupyterlabNotebookCodeFormatter extends JupyterlabCodeFormatter {
120
151
  }
121
152
  }
122
153
  }
123
- async formatCells(selectedOnly, config, formatter, notebook) {
154
+ async formatCells(selectedOnly, config, context, formatter, notebook) {
124
155
  if (this.working) {
125
156
  return;
126
157
  }
@@ -132,10 +163,10 @@ export class JupyterlabNotebookCodeFormatter extends JupyterlabCodeFormatter {
132
163
  return;
133
164
  }
134
165
  const formattersToUse = await this.getFormattersToUse(config, formatter);
135
- await this.applyFormatters(selectedCells, formattersToUse, config);
166
+ await this.applyFormatters(selectedCells, formattersToUse, config, context);
136
167
  }
137
168
  catch (error) {
138
- await showErrorMessage('Jupyterlab Code Formatter Error', error);
169
+ await showErrorMessage('Jupyterlab Code Formatter Error', `${error}`);
139
170
  }
140
171
  this.working = false;
141
172
  }
@@ -151,28 +182,90 @@ export class JupyterlabFileEditorCodeFormatter extends JupyterlabCodeFormatter {
151
182
  this.editorTracker = editorTracker;
152
183
  }
153
184
  formatAction(config, formatter) {
185
+ return this.formatEditor(config, { saving: false }, formatter);
186
+ }
187
+ async formatEditor(config, context, formatter) {
154
188
  if (this.working) {
155
189
  return;
156
190
  }
157
- const editorWidget = this.editorTracker.currentWidget;
158
- this.working = true;
159
- const editor = editorWidget.content.editor;
160
- const code = editor.model.sharedModel.source;
161
- this.formatCode([code], formatter, config[formatter], false, config.cacheFormatters)
162
- .then(data => {
163
- if (data.code[0].error) {
164
- void showErrorMessage('Jupyterlab Code Formatter Error', data.code[0].error);
165
- this.working = false;
166
- return;
191
+ try {
192
+ this.working = true;
193
+ const formattersToUse = await this.getFormattersToUse(config, formatter);
194
+ await this.applyFormatters(formattersToUse, config, context);
195
+ }
196
+ catch (error) {
197
+ const msg = error instanceof Error ? error : `${error}`;
198
+ await showErrorMessage('Jupyterlab Code Formatter Error', msg);
199
+ }
200
+ this.working = false;
201
+ }
202
+ getEditorType() {
203
+ if (!this.editorTracker.currentWidget) {
204
+ return null;
205
+ }
206
+ const mimeType = this.editorTracker.currentWidget.content.model.mimeType;
207
+ const mimeTypes = new Map([
208
+ ['text/x-python', 'python'],
209
+ ['application/x-rsrc', 'r'],
210
+ ['application/x-scala', 'scala'],
211
+ ['application/x-rustsrc', 'rust'],
212
+ ['application/x-c++src', 'cpp'] // Not sure that this is right, whatever.
213
+ // Add more MIME types and corresponding programming languages here
214
+ ]);
215
+ return mimeTypes.get(mimeType);
216
+ }
217
+ getDefaultFormatters(config) {
218
+ const editorType = this.getEditorType();
219
+ if (editorType) {
220
+ const defaultFormatter = config.preferences.default_formatter[editorType];
221
+ if (defaultFormatter instanceof Array) {
222
+ return defaultFormatter;
167
223
  }
168
- this.editorTracker.currentWidget.content.editor.model.sharedModel.source =
169
- data.code[0].code;
170
- this.working = false;
171
- })
172
- .catch(error => {
173
- this.working = false;
174
- void showErrorMessage('Jupyterlab Code Formatter Error', error);
175
- });
224
+ else if (defaultFormatter !== undefined) {
225
+ return [defaultFormatter];
226
+ }
227
+ }
228
+ return [];
229
+ }
230
+ async getFormattersToUse(config, formatter) {
231
+ const defaultFormatters = this.getDefaultFormatters(config);
232
+ const formattersToUse = formatter !== undefined ? [formatter] : defaultFormatters;
233
+ if (formattersToUse.length === 0) {
234
+ await showErrorMessage('Jupyterlab Code Formatter Error', 'Unable to find default formatters to use, please file an issue on GitHub.');
235
+ }
236
+ return formattersToUse;
237
+ }
238
+ async applyFormatters(formattersToUse, config, context) {
239
+ var _a, _b;
240
+ for (const formatterToUse of formattersToUse) {
241
+ if (formatterToUse === 'noop' || formatterToUse === 'skip') {
242
+ continue;
243
+ }
244
+ const showErrors = !((_a = config.suppressFormatterErrors) !== null && _a !== void 0 ? _a : false) &&
245
+ !(((_b = config.suppressFormatterErrorsIFFAutoFormatOnSave) !== null && _b !== void 0 ? _b : false) &&
246
+ context.saving);
247
+ const editorWidget = this.editorTracker.currentWidget;
248
+ this.working = true;
249
+ const editor = editorWidget.content.editor;
250
+ const code = editor.model.sharedModel.source;
251
+ this.formatCode([code], formatterToUse, config[formatterToUse], false, config.cacheFormatters)
252
+ .then(data => {
253
+ if (data.code[0].error) {
254
+ if (showErrors) {
255
+ void showErrorMessage('Jupyterlab Code Formatter Error', data.code[0].error);
256
+ }
257
+ this.working = false;
258
+ return;
259
+ }
260
+ this.editorTracker.currentWidget.content.editor.model.sharedModel.source =
261
+ data.code[0].code;
262
+ this.working = false;
263
+ })
264
+ .catch(error => {
265
+ const msg = error instanceof Error ? error : `${error}`;
266
+ void showErrorMessage('Jupyterlab Code Formatter Error', msg);
267
+ });
268
+ }
176
269
  }
177
270
  applicable(formatter, currentWidget) {
178
271
  const currentEditorWidget = this.editorTracker.currentWidget;
package/lib/index.js CHANGED
@@ -33,7 +33,7 @@ class JupyterLabCodeFormatter {
33
33
  svgstr: Constants.ICON_FORMAT_ALL_SVG
34
34
  }),
35
35
  onClick: async () => {
36
- await this.notebookCodeFormatter.formatAllCodeCells(this.config, undefined, nb.content);
36
+ await this.notebookCodeFormatter.formatAllCodeCells(this.config, { saving: false }, undefined, nb.content);
37
37
  }
38
38
  });
39
39
  nb.toolbar.insertAfter('cellType', this.app.commands.label(Constants.FORMAT_ALL_COMMAND), button);
@@ -44,11 +44,28 @@ class JupyterLabCodeFormatter {
44
44
  }
45
45
  async onSave(context, state) {
46
46
  if (state === 'started' && this.config.formatOnSave) {
47
- await this.notebookCodeFormatter.formatAllCodeCells(this.config);
47
+ await context.sessionContext.ready;
48
+ await this.notebookCodeFormatter.formatAllCodeCells(this.config, { saving: true }, undefined, undefined);
49
+ }
50
+ }
51
+ createNewEditor(widget, context) {
52
+ // Connect to save(State) signal, to be able to detect document save event
53
+ context.saveState.connect(this.onSaveEditor, this);
54
+ // Return an empty disposable, because we don't create any object
55
+ return new DisposableDelegate(() => { });
56
+ }
57
+ async onSaveEditor(context, state) {
58
+ if (state === 'started' && this.config.formatOnSave) {
59
+ this.fileEditorCodeFormatter.formatEditor(this.config, { saving: true }, undefined);
48
60
  }
49
61
  }
50
62
  setupWidgetExtension() {
51
63
  this.app.docRegistry.addWidgetExtension('Notebook', this);
64
+ this.app.docRegistry.addWidgetExtension('editor', {
65
+ createNew: (widget, context) => {
66
+ return this.createNewEditor(widget, context);
67
+ }
68
+ });
52
69
  }
53
70
  setupContextMenu() {
54
71
  this.app.contextMenu.addItem({
@@ -80,7 +97,9 @@ class JupyterLabCodeFormatter {
80
97
  });
81
98
  this.app.commands.addCommand(Constants.FORMAT_ALL_COMMAND, {
82
99
  execute: async () => {
83
- await this.notebookCodeFormatter.formatAllCodeCells(this.config);
100
+ await this.notebookCodeFormatter.formatAllCodeCells(this.config, {
101
+ saving: false
102
+ });
84
103
  },
85
104
  iconClass: Constants.ICON_FORMAT_ALL,
86
105
  iconLabel: 'Format notebook'
package/package.json CHANGED
@@ -1,15 +1,15 @@
1
1
  {
2
2
  "name": "jupyterlab_code_formatter",
3
- "version": "2.2.1",
3
+ "version": "3.0.2",
4
4
  "description": " A JupyterLab plugin to facilitate invocation of code formatters.",
5
5
  "keywords": [
6
6
  "jupyter",
7
7
  "jupyterlab",
8
8
  "jupyterlab-extension"
9
9
  ],
10
- "homepage": " https://github.com/ryantam626/jupyterlab_code_formatter",
10
+ "homepage": " https://github.com/jupyterlab-contrib/jupyterlab_code_formatter",
11
11
  "bugs": {
12
- "url": " https://github.com/ryantam626/jupyterlab_code_formatter/issues"
12
+ "url": " https://github.com/jupyterlab-contrib/jupyterlab_code_formatter/issues"
13
13
  },
14
14
  "license": "BSD-3-Clause",
15
15
  "author": {
@@ -26,7 +26,7 @@
26
26
  "style": "style/index.css",
27
27
  "repository": {
28
28
  "type": "git",
29
- "url": " https://github.com/ryantam626/jupyterlab_code_formatter.git"
29
+ "url": " https://github.com/jupyterlab-contrib/jupyterlab_code_formatter.git"
30
30
  },
31
31
  "scripts": {
32
32
  "build": "jlpm build:lib && jlpm build:labextension:dev",
@@ -56,36 +56,40 @@
56
56
  "watch:labextension": "jupyter labextension watch ."
57
57
  },
58
58
  "dependencies": {
59
- "@jupyterlab/application": "^3.6.0 || ~4.0.0",
60
- "@jupyterlab/coreutils": "^5.1.0",
61
- "@jupyterlab/fileeditor": "^3.6.0 || ~4.0.0",
62
- "@jupyterlab/mainmenu": "^3.6.0 || ~4.0.0",
63
- "@jupyterlab/services": "^6.1.0",
64
- "@jupyterlab/settingregistry": "^3.6.0 || ~4.0.0"
59
+ "@jupyterlab/application": "^4.0.0",
60
+ "@jupyterlab/coreutils": "^6.0.0",
61
+ "@jupyterlab/fileeditor": "^4.0.0",
62
+ "@jupyterlab/mainmenu": "^4.0.0",
63
+ "@jupyterlab/services": "^7.0.0",
64
+ "@jupyterlab/settingregistry": "^4.0.0"
65
65
  },
66
66
  "devDependencies": {
67
- "@babel/core": "^7.0.0",
68
- "@babel/preset-env": "^7.0.0",
69
- "@jupyterlab/builder": "^3.6.0 || ~4.0.0",
70
- "@jupyterlab/testutils": "^3.6.0 || ~4.0.0",
71
- "@types/jest": "^26.0.0",
72
- "@typescript-eslint/eslint-plugin": "^4.8.1",
73
- "@typescript-eslint/parser": "^4.8.1",
74
- "eslint": "^7.14.0",
75
- "eslint-config-prettier": "^6.15.0",
76
- "eslint-plugin-prettier": "^3.1.4",
77
- "jest": "^26.0.0",
67
+ "@jupyterlab/builder": "^4.2.3",
68
+ "@jupyterlab/testutils": "^4.0.0",
69
+ "@types/jest": "^29.2.0",
70
+ "@types/json-schema": "^7.0.11",
71
+ "@types/react": "^18.0.26",
72
+ "@types/react-addons-linked-state-mixin": "^0.14.22",
73
+ "@typescript-eslint/eslint-plugin": "^6.1.0",
74
+ "@typescript-eslint/parser": "^6.1.0",
75
+ "css-loader": "^6.7.1",
76
+ "eslint": "^8.36.0",
77
+ "eslint-config-prettier": "^8.8.0",
78
+ "eslint-plugin-prettier": "^5.0.0",
79
+ "jest": "^29.2.0",
78
80
  "mkdirp": "^1.0.3",
79
81
  "npm-run-all": "^4.1.5",
80
- "prettier": "^2.1.1",
81
- "rimraf": "^3.0.2",
82
- "stylelint": "^14.3.0",
83
- "stylelint-config-prettier": "^9.0.4",
84
- "stylelint-config-recommended": "^6.0.0",
85
- "stylelint-config-standard": "~24.0.0",
86
- "stylelint-prettier": "^2.0.0",
87
- "ts-jest": "^26.0.0",
88
- "typescript": "~4.1.3"
82
+ "prettier": "^3.0.0",
83
+ "rimraf": "^5.0.1",
84
+ "source-map-loader": "^1.0.2",
85
+ "style-loader": "^3.3.1",
86
+ "stylelint": "^15.10.1",
87
+ "stylelint-config-recommended": "^13.0.0",
88
+ "stylelint-config-standard": "^34.0.0",
89
+ "stylelint-csstree-validator": "^3.0.0",
90
+ "stylelint-prettier": "^4.0.0",
91
+ "typescript": "~5.0.2",
92
+ "yjs": "^13.5.0"
89
93
  },
90
94
  "sideEffects": [
91
95
  "style/*.css",
@@ -177,7 +181,15 @@
177
181
  "singleQuote": true,
178
182
  "trailingComma": "none",
179
183
  "arrowParens": "avoid",
180
- "endOfLine": "auto"
184
+ "endOfLine": "auto",
185
+ "overrides": [
186
+ {
187
+ "files": "package.json",
188
+ "options": {
189
+ "tabWidth": 4
190
+ }
191
+ }
192
+ ]
181
193
  },
182
194
  "stylelint": {
183
195
  "extends": [
@@ -185,7 +197,11 @@
185
197
  "stylelint-config-standard",
186
198
  "stylelint-prettier/recommended"
187
199
  ],
200
+ "plugins": [
201
+ "stylelint-csstree-validator"
202
+ ],
188
203
  "rules": {
204
+ "csstree/validator": true,
189
205
  "property-no-vendor-prefix": null,
190
206
  "selector-no-vendor-prefix": null,
191
207
  "value-no-vendor-prefix": null
@@ -208,6 +208,13 @@
208
208
  "additionalProperties": false,
209
209
  "type": "object"
210
210
  },
211
+ "ruffformat": {
212
+ "properties": {
213
+ "args": { "type": "array", "items": { "type": "string" } }
214
+ },
215
+ "additionalProperties": false,
216
+ "type": "object"
217
+ },
211
218
  "formatR": {
212
219
  "properties": {
213
220
  "comment": {
@@ -313,6 +320,10 @@
313
320
  "suppressFormatterErrors": {
314
321
  "additionalProperties": false,
315
322
  "type": "boolean"
323
+ },
324
+ "suppressFormatterErrorsIFFAutoFormatOnSave": {
325
+ "additionalProperties": false,
326
+ "type": "boolean"
316
327
  }
317
328
  },
318
329
  "properties": {
@@ -403,11 +414,19 @@
403
414
  }
404
415
  },
405
416
  "ruff": {
406
- "title": "Ruff Config",
407
- "description": "Command line options to be passed to ruff.",
417
+ "title": "Ruff Check Config",
418
+ "description": "Command line options to be passed to ruff check. Default is to organise imports.",
408
419
  "$ref": "#/definitions/ruff",
409
420
  "default": {
410
- "args": ["--select=I"]
421
+ "args": ["--select=I001"]
422
+ }
423
+ },
424
+ "ruffformat": {
425
+ "title": "Ruff Format Config",
426
+ "description": "Command line options to be passed to ruff format.",
427
+ "$ref": "#/definitions/ruffformat",
428
+ "default": {
429
+ "args": []
411
430
  }
412
431
  },
413
432
  "suppressFormatterErrors": {
@@ -415,6 +434,12 @@
415
434
  "description": "Whether to suppress all errors reported by formatter while formatting. Useful when you have format on save mode on.",
416
435
  "$ref": "#/definitions/suppressFormatterErrors",
417
436
  "default": false
437
+ },
438
+ "suppressFormatterErrorsIFFAutoFormatOnSave": {
439
+ "title": "Suppress formatter errors if and only if auto saving.",
440
+ "description": "Whether to suppress all errors reported by formatter while formatting (if and only if auto saving). Useful when you have format on save mode on and still want to see error when manually formatting.",
441
+ "$ref": "#/definitions/suppressFormatterErrorsIFFAutoFormatOnSave",
442
+ "default": false
418
443
  }
419
444
  },
420
445
  "additionalProperties": false,