int tests pass
This commit is contained in:
@@ -6,10 +6,15 @@ module.exports = {
|
|||||||
testPathIgnorePatterns: [
|
testPathIgnorePatterns: [
|
||||||
'node_modules',
|
'node_modules',
|
||||||
'src/admin/*',
|
'src/admin/*',
|
||||||
|
'dist',
|
||||||
],
|
],
|
||||||
testTimeout: 15000,
|
testTimeout: 15000,
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/src/mocks/fileMock.js',
|
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/tests/mocks/fileMock.js',
|
||||||
'\\.(css|scss)$': '<rootDir>/src/mocks/emptyModule.js',
|
'\\.(css|scss)$': '<rootDir>/tests/mocks/emptyModule.js',
|
||||||
|
},
|
||||||
|
transform: {
|
||||||
|
'\\.(css|less|scss)$': './tests/stub-transformer.js',
|
||||||
|
'\\.(js|jsx|ts|tsx)$': 'babel-jest',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ module.exports = {
|
|||||||
testRegex: '(/src/admin/.*\\.(test|spec))\\.[jt]sx?$',
|
testRegex: '(/src/admin/.*\\.(test|spec))\\.[jt]sx?$',
|
||||||
setupFilesAfterEnv: ['<rootDir>/tests/client/globalSetup.js'],
|
setupFilesAfterEnv: ['<rootDir>/tests/client/globalSetup.js'],
|
||||||
moduleNameMapper: {
|
moduleNameMapper: {
|
||||||
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/src/mocks/fileMock.js',
|
'\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': '<rootDir>/src/mocks/fileMock.ts',
|
||||||
'\\.(css|scss)$': '<rootDir>/src/mocks/emptyModule.js',
|
'\\.(css|scss)$': '<rootDir>/src/mocks/emptyModule.ts',
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -72,7 +72,7 @@
|
|||||||
"is-url": "^1.2.4",
|
"is-url": "^1.2.4",
|
||||||
"isomorphic-fetch": "^2.2.1",
|
"isomorphic-fetch": "^2.2.1",
|
||||||
"isomorphic-style-loader": "^5.1.0",
|
"isomorphic-style-loader": "^5.1.0",
|
||||||
"jest": "^25.3.0",
|
"jest": "26.6.3",
|
||||||
"jsonwebtoken": "^8.5.1",
|
"jsonwebtoken": "^8.5.1",
|
||||||
"jwt-decode": "^3.0.0",
|
"jwt-decode": "^3.0.0",
|
||||||
"method-override": "^3.0.0",
|
"method-override": "^3.0.0",
|
||||||
@@ -210,6 +210,7 @@
|
|||||||
"graphql-request": "^2.0.0",
|
"graphql-request": "^2.0.0",
|
||||||
"mongodb": "^3.6.2",
|
"mongodb": "^3.6.2",
|
||||||
"nodemon": "^1.19.4",
|
"nodemon": "^1.19.4",
|
||||||
|
"ts-jest": "^26.4.4",
|
||||||
"typescript": "^4.1.2",
|
"typescript": "^4.1.2",
|
||||||
"webpack-cli": "^4.1.0"
|
"webpack-cli": "^4.1.0"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -1,8 +1,10 @@
|
|||||||
require('isomorphic-fetch');
|
import { MongoClient } from 'mongodb';
|
||||||
const { MongoClient } = require('mongodb');
|
import getConfig from '../utilities/getConfig';
|
||||||
const { email, password, mongo: { url: mongoURL, port: mongoPort, name: mongoDBName } } = require('../../tests/api/credentials');
|
import { email, password, mongo } from '../../tests/api/credentials';
|
||||||
|
|
||||||
const getConfig = require('../utilities/getConfig');
|
require('isomorphic-fetch');
|
||||||
|
|
||||||
|
const { url: mongoURL, port: mongoPort, name: mongoDBName } = mongo;
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
const { serverURL: url } = getConfig();
|
||||||
|
|
||||||
|
|||||||
@@ -17,5 +17,11 @@ module.exports = {
|
|||||||
require.resolve('@babel/plugin-transform-runtime'),
|
require.resolve('@babel/plugin-transform-runtime'),
|
||||||
require.resolve('@babel/plugin-proposal-class-properties'),
|
require.resolve('@babel/plugin-proposal-class-properties'),
|
||||||
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
require.resolve('@babel/plugin-proposal-optional-chaining'),
|
||||||
|
[
|
||||||
|
'babel-plugin-ignore-html-and-css-imports',
|
||||||
|
{
|
||||||
|
removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'],
|
||||||
|
},
|
||||||
|
],
|
||||||
],
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,11 +1,11 @@
|
|||||||
/**
|
/**
|
||||||
* @jest-environment node
|
* @jest-environment node
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line no-unused-vars
|
import { request, GraphQLClient } from 'graphql-request';
|
||||||
const fetch = require('isomorphic-fetch');
|
import getConfig from '../../../utilities/getConfig';
|
||||||
const { request, GraphQLClient } = require('graphql-request');
|
import { email, password } from '../../../../tests/api/credentials';
|
||||||
const getConfig = require('../../../utilities/getConfig');
|
|
||||||
const { email, password } = require('../../../../tests/api/credentials');
|
require('isomorphic-fetch');
|
||||||
|
|
||||||
const config = getConfig();
|
const config = getConfig();
|
||||||
|
|
||||||
|
|||||||
@@ -1,7 +1,8 @@
|
|||||||
|
import { v4 as uuid } from 'uuid';
|
||||||
|
import getConfig from '../../utilities/getConfig';
|
||||||
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
const uuid = require('uuid').v4;
|
|
||||||
const getConfig = require('../../utilities/getConfig');
|
|
||||||
const { email, password } = require('../../../tests/api/credentials');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
const { serverURL: url } = getConfig();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import getConfig from '../../utilities/getConfig';
|
||||||
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
const getConfig = require('../../utilities/getConfig');
|
|
||||||
const { email, password } = require('../../../tests/api/credentials');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
const { serverURL: url } = getConfig();
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
|
import getConfig from '../../utilities/getConfig';
|
||||||
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
const getConfig = require('../../utilities/getConfig');
|
|
||||||
const { email, password } = require('../../../tests/api/credentials');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
const { serverURL: url } = getConfig();
|
||||||
|
|
||||||
|
|||||||
@@ -1,10 +1,11 @@
|
|||||||
|
import fs from 'fs';
|
||||||
|
import path from 'path';
|
||||||
|
import FormData from 'form-data';
|
||||||
|
import getConfig from '../../utilities/getConfig';
|
||||||
|
import fileExists from '../../../tests/api/utils/fileExists';
|
||||||
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
const fs = require('fs');
|
|
||||||
const path = require('path');
|
|
||||||
const FormData = require('form-data');
|
|
||||||
const getConfig = require('../../utilities/getConfig');
|
|
||||||
const fileExists = require('../../../tests/api/utils/fileExists');
|
|
||||||
const { email, password } = require('../../../tests/api/credentials');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
const { serverURL: url } = getConfig();
|
||||||
|
|
||||||
|
|||||||
33
src/dev.js
33
src/dev.js
@@ -1,21 +1,24 @@
|
|||||||
const babelConfig = require('./babel.config');
|
const babelConfig = require('./babel.config');
|
||||||
|
|
||||||
require('@babel/register')({
|
if (process.env.NODE_ENV !== 'test') {
|
||||||
...babelConfig,
|
// eslint-disable-next-line global-require
|
||||||
ignore: [
|
require('@babel/register')({
|
||||||
/node_modules[\\/](?!@payloadcms[\\/]payload[\\/]src[\\/]admin|@payloadcms[\\/]payload[\\/]components|@payloadcms[\\/]payload[\\/]hooks).*/,
|
...babelConfig,
|
||||||
],
|
ignore: [
|
||||||
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
/node_modules[\\/](?!@payloadcms[\\/]payload[\\/]src[\\/]admin|@payloadcms[\\/]payload[\\/]components|@payloadcms[\\/]payload[\\/]hooks).*/,
|
||||||
plugins: [
|
|
||||||
[
|
|
||||||
'babel-plugin-ignore-html-and-css-imports',
|
|
||||||
{
|
|
||||||
removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'],
|
|
||||||
},
|
|
||||||
],
|
],
|
||||||
...babelConfig.plugins,
|
extensions: ['.js', '.jsx', '.ts', '.tsx'],
|
||||||
],
|
plugins: [
|
||||||
});
|
[
|
||||||
|
'babel-plugin-ignore-html-and-css-imports',
|
||||||
|
{
|
||||||
|
removeExtensions: ['.svg', '.css', '.scss', '.png', '.jpg'],
|
||||||
|
},
|
||||||
|
],
|
||||||
|
...babelConfig.plugins,
|
||||||
|
],
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const payload = require('./index.ts');
|
const payload = require('./index.ts');
|
||||||
|
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
const { APIError } = require('.');
|
import { APIError } from '.';
|
||||||
|
|
||||||
describe('Errors', () => {
|
describe('Errors', () => {
|
||||||
describe('APIError', () => {
|
describe('APIError', () => {
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
|
import Logger from '../../utilities/logger';
|
||||||
import errorHandler from './errorHandler';
|
import errorHandler from './errorHandler';
|
||||||
import { APIError } from '../../errors';
|
import { APIError } from '../../errors';
|
||||||
|
|
||||||
|
const logger = Logger();
|
||||||
|
|
||||||
const testError = new APIError('test error', 503);
|
const testError = new APIError('test error', 503);
|
||||||
|
|
||||||
const mockResponse = () => {
|
const mockResponse = () => {
|
||||||
@@ -38,7 +41,7 @@ describe('errorHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should send the response with the error', async () => {
|
it('should send the response with the error', async () => {
|
||||||
const handler = errorHandler({ debug: true, hooks: {} });
|
const handler = errorHandler({ debug: true, hooks: {} }, logger);
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(res.send)
|
expect(res.send)
|
||||||
.toHaveBeenCalledWith(
|
.toHaveBeenCalledWith(
|
||||||
@@ -47,7 +50,7 @@ describe('errorHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should include stack trace when config debug is on', async () => {
|
it('should include stack trace when config debug is on', async () => {
|
||||||
const handler = errorHandler({ debug: true, hooks: {} });
|
const handler = errorHandler({ debug: true, hooks: {} }, logger);
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(res.send)
|
expect(res.send)
|
||||||
.toHaveBeenCalledWith(
|
.toHaveBeenCalledWith(
|
||||||
@@ -56,7 +59,7 @@ describe('errorHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not include stack trace when config debug is not set', async () => {
|
it('should not include stack trace when config debug is not set', async () => {
|
||||||
const handler = errorHandler({ hooks: {} });
|
const handler = errorHandler({ hooks: {} }, logger);
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(res.send)
|
expect(res.send)
|
||||||
.toHaveBeenCalledWith(
|
.toHaveBeenCalledWith(
|
||||||
@@ -65,7 +68,7 @@ describe('errorHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should not include stack trace when config debug is false', async () => {
|
it('should not include stack trace when config debug is false', async () => {
|
||||||
const handler = errorHandler({ debug: false, hooks: {} });
|
const handler = errorHandler({ debug: false, hooks: {} }, logger);
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(res.send)
|
expect(res.send)
|
||||||
.toHaveBeenCalledWith(
|
.toHaveBeenCalledWith(
|
||||||
@@ -74,7 +77,7 @@ describe('errorHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should show the status code when given an error with a code', async () => {
|
it('should show the status code when given an error with a code', async () => {
|
||||||
const handler = errorHandler({ debug: false, hooks: {} });
|
const handler = errorHandler({ debug: false, hooks: {} }, logger);
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(res.status)
|
expect(res.status)
|
||||||
.toHaveBeenCalledWith(
|
.toHaveBeenCalledWith(
|
||||||
@@ -83,7 +86,7 @@ describe('errorHandler', () => {
|
|||||||
});
|
});
|
||||||
|
|
||||||
it('should default to 500 when an error does not have a status code', async () => {
|
it('should default to 500 when an error does not have a status code', async () => {
|
||||||
const handler = errorHandler({ debug: false, hooks: {} });
|
const handler = errorHandler({ debug: false, hooks: {} }, logger);
|
||||||
testError.status = undefined;
|
testError.status = undefined;
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(res.status)
|
expect(res.status)
|
||||||
@@ -97,7 +100,7 @@ describe('errorHandler', () => {
|
|||||||
const handler = errorHandler({
|
const handler = errorHandler({
|
||||||
debug: false,
|
debug: false,
|
||||||
hooks: { afterError },
|
hooks: { afterError },
|
||||||
});
|
}, logger);
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(afterError)
|
expect(afterError)
|
||||||
.toHaveBeenCalled();
|
.toHaveBeenCalled();
|
||||||
@@ -107,7 +110,7 @@ describe('errorHandler', () => {
|
|||||||
const handler = errorHandler({
|
const handler = errorHandler({
|
||||||
debug: false,
|
debug: false,
|
||||||
hooks: {},
|
hooks: {},
|
||||||
});
|
}, logger);
|
||||||
await handler(testError, req, res);
|
await handler(testError, req, res);
|
||||||
expect(req.collection.config.hooks.afterError)
|
expect(req.collection.config.hooks.afterError)
|
||||||
.toHaveBeenCalled();
|
.toHaveBeenCalled();
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
import httpStatus from 'http-status';
|
import httpStatus from 'http-status';
|
||||||
import formatErrorResponse from '../responses/formatError';
|
import formatErrorResponse from '../responses/formatError';
|
||||||
|
|
||||||
const errorHandler = (payload) => async (err, req, res, next) => {
|
const errorHandler = (config, logger) => async (err, req, res, next) => {
|
||||||
const { config } = payload;
|
|
||||||
const data = formatErrorResponse(err);
|
const data = formatErrorResponse(err);
|
||||||
let response;
|
let response;
|
||||||
let status = err.status || httpStatus.INTERNAL_SERVER_ERROR;
|
let status = err.status || httpStatus.INTERNAL_SERVER_ERROR;
|
||||||
|
|
||||||
payload.logger.error(err.stack);
|
logger.error(err.stack);
|
||||||
|
|
||||||
if (config.debug && config.debug === true) {
|
if (config.debug && config.debug === true) {
|
||||||
data.stack = err.stack;
|
data.stack = err.stack;
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/* eslint-disable jest/require-to-throw-message */
|
import sanitizeFields from './sanitize';
|
||||||
const sanitizeFields = require('./sanitize');
|
import { MissingFieldType, InvalidFieldRelationship } from '../errors';
|
||||||
const { MissingFieldType, InvalidFieldRelationship } = require('../errors');
|
|
||||||
|
|
||||||
describe('sanitizeFields', () => {
|
describe('sanitizeFields', () => {
|
||||||
it('should throw on missing type field', () => {
|
it('should throw on missing type field', () => {
|
||||||
|
|||||||
@@ -2,9 +2,10 @@
|
|||||||
* @jest-environment node
|
* @jest-environment node
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
import getConfig from '../../utilities/getConfig';
|
||||||
|
import { email, password } from '../../../tests/api/credentials';
|
||||||
|
|
||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
const getConfig = require('../../utilities/getConfig');
|
|
||||||
const { email, password } = require('../../../tests/api/credentials');
|
|
||||||
|
|
||||||
const { serverURL: url } = getConfig();
|
const { serverURL: url } = getConfig();
|
||||||
|
|
||||||
@@ -136,7 +136,7 @@ class Payload {
|
|||||||
// Enable static routes for all collections permitting upload
|
// Enable static routes for all collections permitting upload
|
||||||
this.initStatic();
|
this.initStatic();
|
||||||
|
|
||||||
this.errorHandler = errorHandler(this);
|
this.errorHandler = errorHandler(this.config, this.logger);
|
||||||
this.router.use(this.errorHandler);
|
this.router.use(this.errorHandler);
|
||||||
|
|
||||||
this.authenticate = authenticate(this.config);
|
this.authenticate = authenticate(this.config);
|
||||||
|
|||||||
@@ -1 +0,0 @@
|
|||||||
export default {};
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
export default 'file-stub';
|
|
||||||
@@ -2,13 +2,11 @@ import falsey from 'falsey';
|
|||||||
import pino from 'pino';
|
import pino from 'pino';
|
||||||
import memoize from 'micro-memoize';
|
import memoize from 'micro-memoize';
|
||||||
|
|
||||||
export default memoize((name = 'payload') => {
|
export default memoize((name = 'payload') => pino({
|
||||||
return pino({
|
name,
|
||||||
name,
|
enabled: falsey(process.env.DISABLE_LOGGING),
|
||||||
enabled: falsey(process.env.DISABLE_LOGGING),
|
prettyPrint: {
|
||||||
prettyPrint: {
|
ignore: 'pid,hostname',
|
||||||
ignore: 'pid,hostname',
|
translateTime: 'HH:MM:ss',
|
||||||
translateTime: 'HH:MM:ss',
|
},
|
||||||
},
|
}));
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
require('isomorphic-fetch');
|
require('isomorphic-fetch');
|
||||||
|
|
||||||
const server = require('../../demo/server');
|
const server = require('../../demo/server');
|
||||||
const getConfig = require('../../src/utilities/getConfig');
|
const getConfig = require('../../src/utilities/getConfig').default;
|
||||||
const { email, password } = require('./credentials');
|
const { email, password } = require('./credentials');
|
||||||
|
|
||||||
const { serverURL } = getConfig();
|
const { serverURL } = getConfig();
|
||||||
|
|||||||
1
tests/mocks/emptyModule.js
Normal file
1
tests/mocks/emptyModule.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module.exports = {};
|
||||||
1
tests/mocks/fileMock.js
Normal file
1
tests/mocks/fileMock.js
Normal file
@@ -0,0 +1 @@
|
|||||||
|
module.exports = 'file-stub';
|
||||||
8
tests/stub-transformer.js
Normal file
8
tests/stub-transformer.js
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
module.exports = {
|
||||||
|
process() {
|
||||||
|
return 'module.exports = {};';
|
||||||
|
},
|
||||||
|
getCacheKey() {
|
||||||
|
return 'stub-transformer';
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -41,13 +41,6 @@
|
|||||||
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
// "baseUrl": "./", /* Base directory to resolve non-absolute module names. */
|
||||||
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
// "paths": {}, /* A series of entries which re-map imports to lookup locations relative to the 'baseUrl'. */
|
||||||
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
// "rootDirs": [], /* List of root folders whose combined content represents the structure of the project at runtime. */
|
||||||
"typeRoots": [
|
|
||||||
"types"
|
|
||||||
], /* List of folders to include type definitions from. */
|
|
||||||
"types": [
|
|
||||||
"node",
|
|
||||||
"jest",
|
|
||||||
], /* Type declaration files to be included in compilation. */
|
|
||||||
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
// "allowSyntheticDefaultImports": true, /* Allow default imports from modules with no default export. This does not affect code emit, just typechecking. */
|
||||||
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
"esModuleInterop": true, /* Enables emit interoperability between CommonJS and ES Modules via creation of namespace objects for all imports. Implies 'allowSyntheticDefaultImports'. */
|
||||||
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
// "preserveSymlinks": true, /* Do not resolve the real path of symlinks. */
|
||||||
@@ -66,7 +59,7 @@
|
|||||||
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
"forceConsistentCasingInFileNames": true, /* Disallow inconsistently-cased references to the same file. */
|
||||||
},
|
},
|
||||||
"include": [
|
"include": [
|
||||||
"src/"
|
"src/",
|
||||||
],
|
],
|
||||||
"exclude": [
|
"exclude": [
|
||||||
"demo",
|
"demo",
|
||||||
|
|||||||
Reference in New Issue
Block a user