@parse/sqs-mq-adapter 2.0.0 → 2.1.1

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.
@@ -20,23 +20,47 @@ jobs:
20
20
  - run: npm ci
21
21
  - run: npm run lint
22
22
  test:
23
- name: Node ${{ matrix.node }}
24
- runs-on: ubuntu-latest
25
23
  strategy:
26
24
  matrix:
27
- node: [ '18', '20', '22' ]
28
- timeout-minutes: 30
25
+ include:
26
+ - name: Parse Server 8, Node.js 18
27
+ NODE_VERSION: 18.20.4
28
+ PARSE_SERVER_VERSION: 8
29
+ - name: Parse Server 8, Node.js 20
30
+ NODE_VERSION: 20.15.1
31
+ PARSE_SERVER_VERSION: 8
32
+ - name: Parse Server 8, Node.js 22
33
+ NODE_VERSION: 22.4.1
34
+ PARSE_SERVER_VERSION: 8
35
+ - name: Parse Server 7, Node.js 18
36
+ NODE_VERSION: 18.20.4
37
+ PARSE_SERVER_VERSION: 7
38
+ - name: Parse Server 7, Node.js 20
39
+ NODE_VERSION: 20.15.1
40
+ PARSE_SERVER_VERSION: 7
41
+ - name: Parse Server 7, Node.js 22
42
+ NODE_VERSION: 22.4.1
43
+ PARSE_SERVER_VERSION: 7
44
+ fail-fast: false
45
+ name: ${{ matrix.name }}
46
+ timeout-minutes: 15
47
+ runs-on: ubuntu-latest
48
+ env:
49
+ NODE_VERSION: ${{ matrix.NODE_VERSION }}
50
+ PARSE_SERVER_VERSION: ${{ matrix.PARSE_SERVER_VERSION }}
29
51
  steps:
30
52
  - uses: actions/checkout@v4
31
- - uses: actions/setup-node@v4
53
+ - name: Use Node.js ${{ matrix.NODE_VERSION }}
54
+ uses: actions/setup-node@v4
32
55
  with:
33
- node-version: ${{ matrix.node }}
56
+ node-version: ${{ matrix.NODE_VERSION }}
34
57
  cache: npm
58
+ - name: Install Parse Server ${{ matrix.PARSE_SERVER_VERSION }}
59
+ run: npm i -DE parse-server@${{ matrix.PARSE_SERVER_VERSION }}
35
60
  - name: Install dependencies
36
61
  run: npm ci
37
- - run: npm run coverage
38
- env:
39
- CI: true
62
+ - name: Run tests
63
+ run: npm run test
40
64
  - name: Upload code coverage
41
65
  uses: codecov/codecov-action@v4
42
66
  with:
package/CHANGELOG.md CHANGED
@@ -1,3 +1,17 @@
1
+ ## [2.1.1](https://github.com/parse-community/parse-server-sqs-mq-adapter/compare/2.1.0...2.1.1) (2026-01-31)
2
+
3
+
4
+ ### Bug Fixes
5
+
6
+ * Security upgrade qs from 6.14.0 to 6.14.1 ([#268](https://github.com/parse-community/parse-server-sqs-mq-adapter/issues/268)) ([a6cf866](https://github.com/parse-community/parse-server-sqs-mq-adapter/commit/a6cf866f76864aea4fabe3f758800c969da4c9b8))
7
+
8
+ # [2.1.0](https://github.com/parse-community/parse-server-sqs-mq-adapter/compare/2.0.0...2.1.0) (2025-07-06)
9
+
10
+
11
+ ### Features
12
+
13
+ * Add official support for Parse Server 7 and 8 ([#162](https://github.com/parse-community/parse-server-sqs-mq-adapter/issues/162)) ([e7e76b3](https://github.com/parse-community/parse-server-sqs-mq-adapter/commit/e7e76b3db52cc29964db1be33c08298fe166f9b6))
14
+
1
15
  # [2.0.0](https://github.com/parse-community/parse-server-sqs-mq-adapter/compare/1.4.0...2.0.0) (2025-07-05)
2
16
 
3
17
 
package/README.md CHANGED
@@ -9,13 +9,15 @@
9
9
 
10
10
  ---
11
11
 
12
- The Parse Server AWS SQS Message Queue Adapter. This adapter allows a work queue to be spread across a cluster of machines.
12
+ The Parse Server AWS SQS Message Queue Adapter integrates Amazon SQS as the underlying message queue for Parse Server. It allows push notifications, jobs and LiveQuery events to be distributed across multiple Parse Server instances.
13
13
 
14
14
  ---
15
15
 
16
16
  - [Installation](#installation)
17
17
  - [Usage](#usage)
18
+ - [Integrate with Parse Server](#integrate-with-parse-server)
18
19
  - [Credentials](#credentials)
20
+ - [Push Notifications](#push-notifications)
19
21
  ## Installation
20
22
 
21
23
  `npm install --save @parse/sqs-mq-adapter`
@@ -38,6 +40,38 @@ config = {
38
40
  const parseServer = new ParseServer(config);
39
41
  ```
40
42
 
43
+
44
+ ### Integrate with Parse Server
45
+
46
+ 1. **Install dependencies**
47
+
48
+ ```bash
49
+ npm install parse-server @parse/sqs-mq-adapter
50
+ ```
51
+
52
+ 2. **Configure the adapter** in your Parse Server configuration:
53
+
54
+ ```js
55
+ const { ParseServer } = require('parse-server');
56
+ const { SQSEventEmitterMQ } = require('@parse/sqs-mq-adapter');
57
+
58
+ const config = {
59
+ databaseURI: 'mongodb://localhost:27017/app',
60
+ appId: 'myAppId',
61
+ masterKey: 'myMasterKey',
62
+ serverURL: 'https://example.com/parse',
63
+ queueOptions: {
64
+ messageQueueAdapter: SQSEventEmitterMQ,
65
+ queueUrl: 'https://sqs.us-east-1.amazonaws.com/XXX/Parse-Queue',
66
+ region: 'us-east-1',
67
+ },
68
+ };
69
+
70
+ const server = new ParseServer(config);
71
+ ```
72
+
73
+ 3. **Start Parse Server** and the adapter will listen to the configured SQS queue.
74
+
41
75
  See: [sqs-consumer](https://www.npmjs.com/package/sqs-consumer#options) for complete list of configuration options.
42
76
 
43
77
  ### Credentials
@@ -74,3 +108,30 @@ config = {
74
108
 
75
109
  const parseServer = new ParseServer(config);
76
110
  ```
111
+
112
+ ### Push Notifications
113
+
114
+ Parse Server sends push notifications as part of its workload using an internal push queue. When sending large amounts of push notifications this may impact other parts of the workload. This adapter allows Parse Server to only enqueue push notifications into a shared push queue so that another, dedicated Parse Server instance can process the push queue and send the push notification to the push service provider.
115
+
116
+ The Parse Server instance that should only enqueue pushes must have set `disablePushWorker: true`. The Parse Server instance that should process and send the enqueued pushes must omit this option, or set `disablePushWorker: false`.
117
+
118
+ ```js
119
+ const { ParseServer } = require('parse-server');
120
+ const { SQSEventEmitterMQ } = require('@parse/sqs-mq-adapter');
121
+
122
+ const config = {
123
+ push: {
124
+ adapter: new MyPushAdapter(),
125
+ queueOptions: {
126
+ messageQueueAdapter: SQSEventEmitterMQ,
127
+ queueUrl: 'https://sqs.us-east-1.amazonaws.com/XXX/Push-Queue',
128
+ region: 'us-east-1',
129
+ disablePushWorker: true,
130
+ },
131
+ },
132
+ };
133
+
134
+ const server = new ParseServer(config);
135
+ ```
136
+
137
+ This works for any instance constellation, with one or multiple instances enqueuing pushes and one or multiple instances sending pushes.
@@ -0,0 +1,45 @@
1
+ import js from '@eslint/js';
2
+ import globals from 'globals';
3
+
4
+ export default [
5
+ js.configs.recommended,
6
+ {
7
+ files: ['**/*.js'],
8
+ ignores: ['node_modules/**'],
9
+ languageOptions: {
10
+ ecmaVersion: 2022,
11
+ sourceType: 'module',
12
+ globals: {
13
+ ...globals.node,
14
+ Parse: 'readonly'
15
+ }
16
+ },
17
+ rules: {
18
+ indent: ["error", 2, { SwitchCase: 1 }],
19
+ "linebreak-style": ["error", "unix"],
20
+ "no-trailing-spaces": "error",
21
+ "eol-last": "error",
22
+ "space-in-parens": ["error", "never"],
23
+ "no-multiple-empty-lines": "warn",
24
+ "prefer-const": "error",
25
+ "space-infix-ops": "error",
26
+ "no-useless-escape": "off",
27
+ "require-atomic-updates": "off",
28
+ "object-curly-spacing": ["error", "always"],
29
+ curly: ["error", "all"],
30
+ "block-spacing": ["error", "always"],
31
+ "no-unused-vars": "off",
32
+ "no-console": "warn"
33
+ },
34
+ },
35
+ {
36
+ files: ['spec/**/*.js'],
37
+ languageOptions: {
38
+ globals: {
39
+ ...globals.node,
40
+ ...globals.jasmine,
41
+ Parse: 'readonly'
42
+ }
43
+ }
44
+ }
45
+ ];
@@ -1,7 +1,7 @@
1
1
  const events = require('events');
2
2
  const { logger } = require('parse-server');
3
- const SQSProducer = require('sqs-producer');
4
- const SQSConsumer = require('sqs-consumer');
3
+ const { Producer: SQSProducer } = require('sqs-producer');
4
+ const { Consumer: SQSConsumer } = require('sqs-consumer');
5
5
 
6
6
  class Publisher {
7
7
  constructor(config) {
@@ -18,9 +18,21 @@ class Publisher {
18
18
  payload = Object.assign({ id: '0', body: message }, channel ? { groupId: channel } : {});
19
19
  }
20
20
 
21
- this.emitter.send(payload, (err) => {
22
- if (err) logger.error(err);
23
- });
21
+ // basic validation to keep error logging synchronous for invalid payloads
22
+ if (typeof payload === 'object' && !Array.isArray(payload) && payload.body === undefined) {
23
+ logger.error(new Error("Object messages must have 'body' prop"));
24
+ return;
25
+ }
26
+ try {
27
+ const result = this.emitter.send(payload);
28
+ if (result && typeof result.catch === 'function') {
29
+ result.catch((err) => {
30
+ logger.error(err);
31
+ });
32
+ }
33
+ } catch (err) {
34
+ logger.error(err);
35
+ }
24
36
  }
25
37
  }
26
38
 
@@ -36,9 +48,8 @@ class Consumer extends events.EventEmitter {
36
48
  subscribe(channel) {
37
49
  this.unsubscribe(channel);
38
50
 
39
- const handleMessage = (message, done) => {
51
+ const handleMessage = async (message) => {
40
52
  this.emit('message', channel, message.Body);
41
- done();
42
53
  };
43
54
 
44
55
  const createOptions = Object.assign(this.config, { handleMessage });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@parse/sqs-mq-adapter",
3
- "version": "2.0.0",
3
+ "version": "2.1.1",
4
4
  "description": "Spread work queue across cluster of parse servers using SQS",
5
5
  "main": "index.js",
6
6
  "repository": {
@@ -10,30 +10,39 @@
10
10
  "author": "Parse Platform",
11
11
  "license": "Apache-2.0",
12
12
  "dependencies": {
13
- "sqs-consumer": "3.8.0",
14
- "sqs-producer": "1.6.3"
13
+ "@aws-sdk/client-sqs": "3.972.0",
14
+ "sqs-consumer": "12.0.0",
15
+ "sqs-producer": "7.0.0"
15
16
  },
16
17
  "peerDependencies": {
17
18
  "parse-server": "*"
18
19
  },
19
20
  "devDependencies": {
21
+ "@eslint/js": "9.32.0",
20
22
  "@semantic-release/changelog": "6.0.3",
21
23
  "@semantic-release/commit-analyzer": "13.0.1",
22
24
  "@semantic-release/git": "10.0.1",
23
- "@semantic-release/github": "11.0.3",
24
- "@semantic-release/npm": "12.0.1",
25
- "@semantic-release/release-notes-generator": "14.0.3",
26
- "eslint": "9.30.1",
27
- "jasmine": "2.99.0",
28
- "nyc": "15.1.0",
29
- "parse-server": "5.5.6",
30
- "semantic-release": "24.2.5",
31
- "sinon": "14.0.0"
25
+ "@semantic-release/github": "12.0.2",
26
+ "@semantic-release/npm": "13.1.3",
27
+ "@semantic-release/release-notes-generator": "14.1.0",
28
+ "eslint": "9.39.2",
29
+ "globals": "17.1.0",
30
+ "jasmine": "6.0.0",
31
+ "jasmine-spec-reporter": "7.0.0",
32
+ "mongodb-runner": "6.5.4",
33
+ "nyc": "17.1.0",
34
+ "parse-server": "9.1.1",
35
+ "semantic-release": "25.0.2"
32
36
  },
33
37
  "scripts": {
34
38
  "lint": "eslint --cache ./index.js ./lib/** ./spec/**/*.js",
35
39
  "lint-fix": "eslint --cache --fix ./index.js ./lib/** ./spec/**/*.js",
36
- "test": "jasmine",
40
+ "pretest": "npm run test:mongodb:runnerstart",
41
+ "posttest": "npm run test:mongodb:runnerstop",
42
+ "test": "npm run test:only",
43
+ "test:only": "TESTING=1 nyc jasmine",
44
+ "test:mongodb:runnerstart": "mongodb-runner start -t standalone -- --port 27017",
45
+ "test:mongodb:runnerstop": "mongodb-runner stop --all",
37
46
  "coverage": "nyc jasmine"
38
47
  },
39
48
  "engines": {
@@ -1,51 +1,36 @@
1
- const sinon = require('sinon');
2
1
  const { ParseMessageQueue } = require('../node_modules/parse-server/lib/ParseMessageQueue');
3
2
  const { SQSEventEmitterMQ } = require('../');
4
3
  const { logger } = require('parse-server');
4
+ const { getServerConfig } = require('./support/server.js');
5
+ const { getMockSqsOptions } = require('./mocks/sqs.js');
5
6
 
6
7
  let config;
7
8
 
8
9
  describe('SMSEventEmitterMQ', () => {
9
10
  beforeEach(() => {
10
- const response = {
11
- Messages: [{
12
- ReceiptHandle: 'receipt-handle',
13
- MessageId: '123',
14
- Body: 'body',
15
- }],
16
- };
17
-
18
- const sqs = sinon.mock();
19
- sqs.sendMessageBatch = sinon.stub();
20
- sqs.receiveMessage = sinon.stub().yieldsAsync(null, response);
21
- sqs.receiveMessage.onSecondCall().returns();
22
- sqs.deleteMessage = sinon.stub();
23
-
24
- config = {
25
- messageQueueAdapter: SQSEventEmitterMQ,
26
- queueUrl: 'test-queue',
27
- region: 'mock',
28
- sqs,
29
- };
11
+ config = getMockSqsOptions();
30
12
  });
31
13
 
32
- xit('a test for real that can be done against a live queue', (done) => {
33
- const CHANNEL = 'foo';
34
- const MESSAGE = 'hi';
35
-
36
- const subscriber = ParseMessageQueue.createSubscriber(config);
37
- const publisher = ParseMessageQueue.createPublisher(config);
14
+ describe('integration', () => {
15
+ it('publishes a message', done => {
16
+ const options = getServerConfig().queueOptions;
17
+ const subscriber = ParseMessageQueue.createSubscriber(options);
18
+ const publisher = ParseMessageQueue.createPublisher(options);
19
+ const channel = 'foo';
20
+ const message = 'hi';
21
+
22
+ subscriber.subscribe(channel);
23
+ subscriber.on('message', (channel, message) => {
24
+ expect(channel).toBe(channel);
25
+ expect(message).toBe(message);
26
+
27
+ // Give aws-sdk some time to mark the message to avoid flaky test
28
+ setTimeout(done, 200);
29
+ });
38
30
 
39
- subscriber.subscribe(CHANNEL);
40
- subscriber.on('message', (channel, message) => {
41
- expect(channel).toBe(CHANNEL);
42
- expect(message).toBe(MESSAGE);
43
- // need to give the aws-sdk some time to mark the message
44
- setTimeout(done, 500);
31
+ publisher.publish(channel, message);
45
32
  });
46
-
47
- publisher.publish(CHANNEL, MESSAGE);
48
- }).pend('configure options for a real sqs endpoint');
33
+ });
49
34
 
50
35
  describe('subscriber', () => {
51
36
  it('should only have one subscription map', () => {
@@ -73,7 +58,7 @@ describe('SMSEventEmitterMQ', () => {
73
58
  subscriber.subscribe('message_processed');
74
59
  subscriber.on('message', (event, message) => {
75
60
  expect(event).toBe('message_processed');
76
- expect(message).toBe('body');
61
+ expect(message).toBe('hi');
77
62
  done();
78
63
  });
79
64
  });
@@ -110,7 +95,7 @@ describe('SMSEventEmitterMQ', () => {
110
95
  { id: '0', body: 'foo', groupId: 'channel' },
111
96
  { id: '1', body: 'bar', groupId: 'channel' },
112
97
  ];
113
- expect(publisher.emitter.send).toHaveBeenCalledWith(payload, jasmine.any(Function));
98
+ expect(publisher.emitter.send).toHaveBeenCalledWith(payload);
114
99
  });
115
100
 
116
101
  it('should process a batch with no channel', () => {
@@ -121,7 +106,7 @@ describe('SMSEventEmitterMQ', () => {
121
106
  { id: '0', body: 'foo' },
122
107
  { id: '1', body: 'bar' },
123
108
  ];
124
- expect(publisher.emitter.send).toHaveBeenCalledWith(payload, jasmine.any(Function));
109
+ expect(publisher.emitter.send).toHaveBeenCalledWith(payload);
125
110
  });
126
111
  });
127
112
  });
@@ -0,0 +1,3 @@
1
+
2
+
3
+
@@ -0,0 +1,34 @@
1
+ const { SQSEventEmitterMQ } = require('../../');
2
+
3
+ function getMockSqsOptions() {
4
+ const response = {
5
+ Messages: [
6
+ {
7
+ ReceiptHandle: 'receipt-handle',
8
+ MessageId: '123',
9
+ Body: 'hi',
10
+ },
11
+ ],
12
+ };
13
+
14
+ let call = 0;
15
+ const sqs = {
16
+ sendMessageBatch: () => Promise.resolve({}),
17
+ send: () => {
18
+ call += 1;
19
+ if (call === 1) {
20
+ return Promise.resolve(response);
21
+ }
22
+ return Promise.resolve({});
23
+ },
24
+ };
25
+
26
+ return {
27
+ messageQueueAdapter: SQSEventEmitterMQ,
28
+ queueUrl: 'test-queue',
29
+ region: 'mock',
30
+ sqs,
31
+ };
32
+ }
33
+
34
+ module.exports = { getMockSqsOptions };
@@ -0,0 +1,16 @@
1
+ 'use strict';
2
+ const { startServer, stopServer, reconfigureServer } = require('./server');
3
+
4
+ jasmine.DEFAULT_TIMEOUT_INTERVAL = process.env.TESTING_TIMEOUT || '360000';
5
+
6
+ beforeAll(async () => {
7
+ await startServer();
8
+ });
9
+
10
+ afterAll(async () => {
11
+ await stopServer();
12
+ });
13
+
14
+ beforeEach(async () => {
15
+ await reconfigureServer();
16
+ });
@@ -0,0 +1,12 @@
1
+ const semver = require('semver');
2
+
3
+ const satisfiesParseServerVersion = version => {
4
+ const envVersion = process.env.PARSE_SERVER_VERSION;
5
+ const semverVersion = semver.coerce(envVersion);
6
+ return !envVersion || !semverVersion || semver.satisfies(semverVersion, version);
7
+ };
8
+
9
+ global.it_only_parse_server_version = version => satisfiesParseServerVersion(version) ? it : xit;
10
+ global.fit_only_parse_server_version = version => satisfiesParseServerVersion(version) ? fit : xit;
11
+ global.describe_only_parse_server_version = version => satisfiesParseServerVersion(version) ? describe : xdescribe;
12
+ global.fdescribe_only_parse_server_version = version => satisfiesParseServerVersion(version) ? fdescribe : xdescribe;
@@ -0,0 +1,13 @@
1
+ {
2
+ "spec_dir": "spec",
3
+ "spec_files": [
4
+ "**/*[sS]pec.js"
5
+ ],
6
+ "helpers": [
7
+ "support/helper.js",
8
+ "support/jasmine.js",
9
+ "support/reporter.js"
10
+ ],
11
+ "stopSpecOnExpectationFailure": false,
12
+ "random": true
13
+ }
@@ -0,0 +1,12 @@
1
+ const { SpecReporter } = require('jasmine-spec-reporter');
2
+
3
+ jasmine.getEnv().clearReporters();
4
+ jasmine.getEnv().addReporter(
5
+ new SpecReporter({
6
+ spec: {
7
+ displayPending: true,
8
+ displayDuration: true,
9
+ displayStacktrace: 'pretty',
10
+ },
11
+ })
12
+ );
@@ -0,0 +1,81 @@
1
+ const { ParseServer } = require('parse-server');
2
+ const express = require('express');
3
+ const http = require('http');
4
+ const { getMockSqsOptions } = require('../mocks/sqs');
5
+ const Config = require('../../node_modules/parse-server/lib/Config.js');
6
+
7
+ const expressApp = express();
8
+ const queueOptions = getMockSqsOptions();
9
+
10
+ let serverState = {};
11
+
12
+ const defaultConfig = {
13
+ databaseURI: 'mongodb://127.0.0.1:27017/sqs-mq-adapter',
14
+ appId: 'test',
15
+ masterKey: 'test',
16
+ maintenanceKey: 'test-maintenance-key',
17
+ serverURL: 'http://127.0.0.1:1327/api/parse',
18
+ port: 1327,
19
+ mountPath: '/api/parse',
20
+ verbose: false,
21
+ silent: true,
22
+ queueOptions,
23
+ verifyUserEmails: false,
24
+ };
25
+
26
+ async function startServer(config = {}) {
27
+ if (!process.env.TESTING) {
28
+ throw 'requires test environment to run';
29
+ }
30
+
31
+ const serverConfig = Object.assign({}, config, defaultConfig);
32
+ const parseServer = ParseServer(serverConfig);
33
+ await parseServer.start();
34
+ expressApp.use(serverConfig.mountPath, parseServer.app);
35
+
36
+ const httpServer = http.createServer(expressApp);
37
+ await new Promise((resolve, reject) => {
38
+ httpServer
39
+ .listen(serverConfig.port)
40
+ .once('listening', resolve)
41
+ .once('error', (e) => reject(e));
42
+ }).catch((e) => {
43
+ throw new Error(`parse-server failed to launch with error: ${e}`);
44
+ });
45
+
46
+ Object.assign(serverState, {
47
+ parseServer,
48
+ httpServer,
49
+ serverConfig,
50
+ });
51
+ }
52
+
53
+ async function stopServer() {
54
+ if (!process.env.TESTING) {
55
+ throw 'requires test environment to run';
56
+ }
57
+
58
+ await Parse.User.logOut();
59
+ const app = Config.get(defaultConfig.appId);
60
+ await app?.database.deleteEverything(true);
61
+
62
+ const { httpServer } = serverState;
63
+ await new Promise((resolve) => httpServer.close(resolve));
64
+ serverState = {};
65
+ }
66
+
67
+ async function reconfigureServer(config = {}) {
68
+ await stopServer();
69
+ return await startServer(config);
70
+ }
71
+
72
+ function getServerConfig() {
73
+ return serverState.serverConfig || defaultConfig;
74
+ }
75
+
76
+ module.exports = {
77
+ reconfigureServer,
78
+ startServer,
79
+ stopServer,
80
+ getServerConfig,
81
+ };
package/eslint.config.js DELETED
@@ -1,41 +0,0 @@
1
- import js from '@eslint/js';
2
- import globals from 'globals';
3
-
4
- export default [
5
- js.configs.recommended,
6
- {
7
- files: ['**/*.js'],
8
- ignores: ['node_modules/**'],
9
- languageOptions: {
10
- ecmaVersion: 6,
11
- sourceType: 'module',
12
- globals: {
13
- ...globals.node,
14
- Parse: 'readonly'
15
- }
16
- },
17
- rules: {
18
- indent: ['error', 2, { SwitchCase: 1 }],
19
- 'linebreak-style': ['error', 'unix'],
20
- 'no-trailing-spaces': 2,
21
- 'eol-last': 2,
22
- 'space-in-parens': ['error', 'never'],
23
- 'no-multiple-empty-lines': 1,
24
- 'prefer-const': 'error',
25
- 'space-infix-ops': 'error',
26
- 'no-useless-escape': 'off',
27
- 'require-atomic-updates': 'off',
28
- 'object-curly-spacing': ['error', 'always']
29
- }
30
- },
31
- {
32
- files: ['spec/**/*.js'],
33
- languageOptions: {
34
- globals: {
35
- ...globals.node,
36
- ...globals.jasmine,
37
- Parse: 'readonly'
38
- }
39
- }
40
- }
41
- ];