Fix strict mode errors in TS

This commit is contained in:
rijkvanzanten
2020-07-21 15:02:30 -04:00
parent 97dd919d94
commit 336e195334
26 changed files with 199 additions and 152 deletions

View File

@@ -53,7 +53,7 @@ export default async function sendMail(options: EmailOptions) {
const templateString = await readFile(path.join(__dirname, 'templates/base.liquid'), 'utf8');
const html = await liquidEngine.parseAndRender(templateString, { html: options.html });
options.from = options.from || process.env.EMAIL_FROM;
options.from = options.from || (process.env.EMAIL_FROM as string);
try {
await transporter.sendMail({ ...options, html: html });

View File

@@ -19,7 +19,7 @@ const authenticate: RequestHandler = asyncHandler(async (req, res, next) => {
let payload: { id: string };
try {
payload = jwt.verify(req.token, process.env.SECRET) as { id: string };
payload = jwt.verify(req.token, process.env.SECRET as string) as { id: string };
} catch (err) {
if (err instanceof TokenExpiredError) {
throw new InvalidCredentialsException('Token expired.');

View File

@@ -18,13 +18,13 @@ const collectionExists: RequestHandler = asyncHandler(async (req, res, next) =>
req.collection = req.params.collection;
const { single } = await database
const collectionInfo = await database
.select('single')
.from('directus_collections')
.where({ collection: req.collection })
.first();
req.single = single;
req.single = collectionInfo?.single || false;
return next();
});

View File

@@ -9,6 +9,7 @@ import { Meta } from '../types/meta';
import logger from '../logger';
const sanitizeQuery: RequestHandler = (req, res, next) => {
req.sanitizedQuery = {};
if (!req.query) return;
const query: Query = {
@@ -16,7 +17,11 @@ const sanitizeQuery: RequestHandler = (req, res, next) => {
};
if (req.query.limit) {
query.limit = sanitizeLimit(req.query.limit);
const limit = sanitizeLimit(req.query.limit);
if (limit) {
query.limit = limit;
}
}
if (req.query.sort) {

View File

@@ -51,10 +51,12 @@ router.get(
);
}
const systemKeys = SYSTEM_ASSET_WHITELIST.map((size) => size.key);
const systemKeys = SYSTEM_ASSET_WHITELIST.map((transformation) => transformation.key);
const allKeys: string[] = [
...systemKeys,
...assetSettings.asset_shortcuts.map((size) => size.key),
...assetSettings.asset_shortcuts.map(
(transformation: Transformation) => transformation.key
),
];
// For use in the next request handler
@@ -86,7 +88,10 @@ router.get(
// Return file
asyncHandler(async (req, res) => {
const transformation: Transformation = res.locals.transformation.key
? res.locals.shortcuts.find((size) => size.key === res.locals.transformation.key)
? res.locals.shortcuts.find(
(transformation: Transformation) =>
transformation.key === res.locals.transformation.key
)
: res.locals.transformation;
const { stream, file } = await AssetsService.getAsset(req.params.pk, transformation);

View File

@@ -59,7 +59,7 @@ router.post(
if (mode === 'cookie') {
res.cookie('directus_refresh_token', refreshToken, {
httpOnly: true,
maxAge: ms(process.env.REFRESH_TOKEN_TTL),
maxAge: ms(process.env.REFRESH_TOKEN_TTL as string),
secure: process.env.REFRESH_TOKEN_COOKIE_SECURE === 'true' ? true : false,
sameSite:
(process.env.REFRESH_TOKEN_COOKIE_SAME_SITE as 'lax' | 'strict' | 'none') ||
@@ -100,7 +100,7 @@ router.post(
if (mode === 'cookie') {
res.cookie('directus_refresh_token', refreshToken, {
httpOnly: true,
maxAge: ms(process.env.REFRESH_TOKEN_TTL),
maxAge: ms(process.env.REFRESH_TOKEN_TTL as string),
secure: process.env.REFRESH_TOKEN_COOKIE_SECURE === 'true' ? true : false,
sameSite:
(process.env.REFRESH_TOKEN_COOKIE_SAME_SITE as 'lax' | 'strict' | 'none') ||
@@ -132,7 +132,7 @@ router.post(
router.use(
'/sso',
session({ secret: process.env.SECRET, saveUninitialized: false, resave: false })
session({ secret: process.env.SECRET as string, saveUninitialized: false, resave: false })
);
router.use(grant.express()(getGrantConfig()));
@@ -143,7 +143,7 @@ router.use(grant.express()(getGrantConfig()));
router.get(
'/sso/:provider/callback',
asyncHandler(async (req, res) => {
const email = getEmailFromProfile(req.params.provider, req.session.grant.response.profile);
const email = getEmailFromProfile(req.params.provider, req.session!.grant.response.profile);
const { accessToken, refreshToken, expires, id } = await AuthService.authenticate(email);

View File

@@ -70,7 +70,7 @@ router.post(
throw new InvalidPayloadException(error.message);
}
const field: Partial<Field> = req.body;
const field: Partial<Field> & { field: string; database: { type: string } } = req.body;
const createdField = await FieldsService.createField(req.collection, field, {
role: req.role,

View File

@@ -5,7 +5,7 @@ import sanitizeQuery from '../middleware/sanitize-query';
import collectionExists from '../middleware/collection-exists';
import * as MetaService from '../services/meta';
import { RouteNotFoundException } from '../exceptions';
import { Accountability } from '../types';
import { Accountability, PrimaryKey } from '../types';
const router = express.Router();
@@ -73,9 +73,9 @@ router.get(
throw new RouteNotFoundException(req.path);
}
const pk = req.params.pk.includes(',') ? req.params.pk.split(',') : req.params.pk;
const primaryKey = req.params.pk.includes(',') ? req.params.pk.split(',') : req.params.pk;
const result = await ItemsService.readItem(req.collection, pk, req.sanitizedQuery, {
const result = await ItemsService.readItem(req.collection, primaryKey, req.sanitizedQuery, {
role: req.role,
admin: req.admin,
});
@@ -130,21 +130,40 @@ router.patch(
};
const primaryKey = req.params.pk.includes(',') ? req.params.pk.split(',') : req.params.pk;
const updatedPrimaryKey = await ItemsService.updateItem(
req.collection,
primaryKey,
req.body,
accountability
);
const result = await ItemsService.readItem(
req.collection,
updatedPrimaryKey,
req.sanitizedQuery,
accountability
);
if (Array.isArray(primaryKey)) {
const updatedPrimaryKey = await ItemsService.updateItem(
req.collection,
primaryKey,
req.body,
accountability
);
res.json({ data: result || null });
const result = await ItemsService.readItem(
req.collection,
updatedPrimaryKey,
req.sanitizedQuery,
accountability
);
res.json({ data: result || null });
} else {
const updatedPrimaryKey = await ItemsService.updateItem(
req.collection,
primaryKey,
req.body,
accountability
);
const result = await ItemsService.readItem(
req.collection,
updatedPrimaryKey,
req.sanitizedQuery,
accountability
);
res.json({ data: result || null });
}
})
);

View File

@@ -1,5 +1,5 @@
import * as ItemsService from './items';
import { Accountability, Item, Query } from '../types';
import { Accountability, Item, Query, PrimaryKey } from '../types';
export enum Action {
CREATE = 'create',
@@ -15,16 +15,16 @@ export const createActivity = async (data: Partial<Item>) => {
return await ItemsService.createItem('directus_activity', data);
};
export const readActivities = async (query?: Query, accountability?: Accountability) => {
export const readActivities = async (query: Query, accountability?: Accountability) => {
return await ItemsService.readItems('directus_activity', query, accountability);
};
export const readActivity = async (
pk: string | number,
query?: Query,
primaryKey: PrimaryKey,
query: Query = {},
accountability?: Accountability
) => {
return await ItemsService.readItem('directus_activity', pk, query, accountability);
return await ItemsService.readItem('directus_activity', primaryKey, query, accountability);
};
export const updateActivity = async (

View File

@@ -9,8 +9,8 @@ import { Session } from '../types/sessions';
type AuthenticateOptions = {
email: string;
password?: string;
ip?: string;
userAgent?: string;
ip?: string | null;
userAgent?: string | null;
};
/**
@@ -45,12 +45,14 @@ export const authenticate = async ({ email, password, ip, userAgent }: Authentic
* Sign token with combination of server secret + user password hash
* That way, old tokens are immediately invalidated whenever the user changes their password
*/
const accessToken = jwt.sign(payload, process.env.SECRET, {
const accessToken = jwt.sign(payload, process.env.SECRET as string, {
expiresIn: process.env.ACCESS_TOKEN_TTL,
});
const refreshToken = nanoid(64);
const refreshTokenExpiration = new Date(Date.now() + ms(process.env.REFRESH_TOKEN_TTL));
const refreshTokenExpiration = new Date(
Date.now() + ms(process.env.REFRESH_TOKEN_TTL as string)
);
await database('directus_sessions').insert({
token: refreshToken,
@@ -63,7 +65,7 @@ export const authenticate = async ({ email, password, ip, userAgent }: Authentic
return {
accessToken,
refreshToken,
expires: ms(process.env.ACCESS_TOKEN_TTL) / 1000,
expires: ms(process.env.ACCESS_TOKEN_TTL as string) / 1000,
id: user.id,
};
};

View File

@@ -67,10 +67,10 @@ export const create = async (payload: any, accountability: Accountability) => {
}))
);
return await ItemsService.readItem('directus_collections', primaryKey);
return await ItemsService.readItem('directus_collections', primaryKey, {});
};
export const readAll = async (query?: Query, accountability?: Accountability) => {
export const readAll = async (query: Query, accountability?: Accountability) => {
const [tables, collections] = await Promise.all([
schemaInspector.tableInfo(),
ItemsService.readItems<Collection>('directus_collections', query, accountability),
@@ -96,7 +96,7 @@ export const readAll = async (query?: Query, accountability?: Accountability) =>
export const readOne = async (
collection: string,
query?: Query,
query: Query,
accountability?: Accountability
) => {
const [table, collectionInfo] = await Promise.all([

View File

@@ -2,7 +2,7 @@ import listFolders from '../utils/list-folders';
import path from 'path';
export async function listExtensions(type: string) {
const extensionsPath = process.env.EXTENSIONS_PATH;
const extensionsPath = process.env.EXTENSIONS_PATH as string;
const location = path.join(extensionsPath, type);
return await listFolders(location);

View File

@@ -64,7 +64,7 @@ export const readOne = async (collection: string, field: string) => {
export const createField = async (
collection: string,
field: Partial<Field>,
field: Partial<Field> & { field: string; database: { type: string } },
accountability: Accountability
) => {
await database.schema.alterTable(collection, (table) => {

View File

@@ -1,8 +1,7 @@
import database, { schemaInspector } from '../database';
import { Query } from '../types/query';
import runAST from '../database/run-ast';
import getASTFromQuery from '../utils/get-ast-from-query';
import { Accountability, Operation, Item } from '../types';
import { Accountability, Operation, Item, Query, PrimaryKey } from '../types';
import Knex from 'knex';
import * as PayloadService from './payload';
@@ -43,27 +42,17 @@ async function saveActivityAndRevision(
}
}
export async function createItem(
export async function createItem<T extends Partial<Item> | Partial<Item>[]>(
collection: string,
data: Partial<Item>[],
data: T,
accountability?: Accountability
): Promise<(string | number)[]>;
export async function createItem(
collection: string,
data: Partial<Item>,
accountability?: Accountability
): Promise<string | number>;
export async function createItem(
collection: string,
data: Partial<Item> | Partial<Item>[],
accountability?: Accountability
): Promise<string | number | (string | number)[]> {
): Promise<T extends Partial<Item>[] ? PrimaryKey[] : PrimaryKey> {
const isBatch = Array.isArray(data);
return database.transaction(async (transaction) => {
const primaryKeys = await database.transaction(async (transaction) => {
let payloads = isBatch ? data : [data];
const primaryKeys: (string | number)[] = await Promise.all(
const primaryKeys: PrimaryKey[] = await Promise.all(
payloads.map(async (payload: Partial<Item>) => {
if (accountability && accountability.admin === false) {
payload = await PermissionsService.processValues(
@@ -106,16 +95,20 @@ export async function createItem(
);
}
return primaryKeys[0];
return primaryKeys[0] as PrimaryKey;
})
);
if (isBatch) {
return primaryKeys;
} else {
return primaryKeys[0];
}
return primaryKeys;
});
if (Array.isArray(data)) {
return primaryKeys as T extends Partial<Record<string, any>>[] ? PrimaryKey[] : PrimaryKey;
} else {
return primaryKeys[0] as T extends Partial<Record<string, any>>[]
? PrimaryKey[]
: PrimaryKey;
}
}
export const readItems = async <T = Partial<Item>>(
@@ -130,23 +123,23 @@ export const readItems = async <T = Partial<Item>>(
}
const records = await runAST(ast);
return await PayloadService.processValues('read', collection, records);
return (await PayloadService.processValues('read', collection, records)) as T[];
};
export const readItem = async <T extends number | string | (number | string)[]>(
export async function readItem<T extends PrimaryKey | PrimaryKey[]>(
collection: string,
pk: T,
query: Query = {},
primaryKey: T,
query: Query,
accountability?: Accountability,
operation?: Operation
): Promise<T extends number | string ? Partial<Item> : Partial<Item>[]> => {
): Promise<T extends PrimaryKey ? Item : Item[]> {
// We allow overriding the operation, so we can use the item read logic to validate permissions
// for update and delete as well
operation = operation || 'read';
const primaryKeyField = await schemaInspector.primary(collection);
const primaryKeys: any[] = Array.isArray(pk) ? pk : [pk];
const isBatch = Array.isArray(pk);
const primaryKeys = (Array.isArray(primaryKey) ? primaryKey : [primaryKey]) as PrimaryKey[];
const isBatch = Array.isArray(primaryKey);
if (isBatch) {
query = {
@@ -164,7 +157,7 @@ export const readItem = async <T extends number | string | (number | string)[]>(
filter: {
...(query.filter || {}),
[primaryKeyField]: {
_eq: pk,
_eq: primaryKey,
},
},
};
@@ -179,15 +172,15 @@ export const readItem = async <T extends number | string | (number | string)[]>(
const records = await runAST(ast);
const processedRecords = await PayloadService.processValues('read', collection, records);
return isBatch ? processedRecords : processedRecords[0];
};
}
export const updateItem = async <T extends number | string | (number | string)[]>(
export async function updateItem<T extends PrimaryKey | PrimaryKey[]>(
collection: string,
pk: T,
primaryKey: T,
data: Partial<Item>,
accountability?: Accountability
): Promise<T> => {
const primaryKeys: any[] = Array.isArray(pk) ? pk : [pk];
): Promise<T> {
const primaryKeys = (Array.isArray(primaryKey) ? primaryKey : [primaryKey]) as PrimaryKey[];
await database.transaction(async (transaction) => {
let payload = clone(data);
@@ -238,13 +231,13 @@ export const updateItem = async <T extends number | string | (number | string)[]
);
}
return pk;
return primaryKey as PrimaryKey;
})
);
});
return pk;
};
return primaryKey;
}
export const deleteItem = async <T extends number | string | (number | string)[]>(
collection: string,
@@ -270,14 +263,16 @@ export const deleteItem = async <T extends number | string | (number | string)[]
.where({ [primaryKeyField]: key })
.delete();
await saveActivityAndRevision(
ActivityService.Action.DELETE,
collection,
String(key),
{},
accountability,
transaction
);
if (accountability) {
await saveActivityAndRevision(
ActivityService.Action.DELETE,
collection,
String(key),
{},
accountability,
transaction
);
}
})
);
});
@@ -297,7 +292,7 @@ export const readSingleton = async (
if (!record) {
const columns = await schemaInspector.columnInfo(collection);
const defaults = {};
const defaults: Record<string, any> = {};
for (const column of columns) {
defaults[column.name] = column.default_value;

View File

@@ -14,7 +14,7 @@ export const getMetaForQuery = async (collection: string, query: Query) => {
return results.reduce((metaObject: Record<string, any>, value, index) => {
return {
...metaObject,
[query.meta[index]]: value,
[query.meta![index]]: value,
};
}, {});
};

View File

@@ -8,8 +8,9 @@ import argon2 from 'argon2';
import { v4 as uuidv4 } from 'uuid';
import database from '../database';
import { clone, isObject } from 'lodash';
import { File, Relation, Item } from '../types';
import { Relation, Item } from '../types';
import * as ItemsService from './items';
import { URL } from 'url';
type Operation = 'create' | 'read' | 'update';
@@ -41,7 +42,7 @@ const transformers: Transformers = {
return value;
},
async 'file-links'(operation, value, payload: File) {
async 'file-links'(operation, value, payload) {
if (operation === 'read' && payload && payload.storage && payload.filename_disk) {
const publicKey = `STORAGE_${payload.storage.toUpperCase()}_PUBLIC_URL`;
@@ -64,16 +65,23 @@ const transformers: Transformers = {
* @param payload The actual payload itself
* @returns The updated payload
*/
export const processValues = async (
export async function processValues(
operation: Operation,
collection: string,
payload: Partial<Item>
): Promise<Partial<Item>>;
export async function processValues(
operation: Operation,
collection: string,
payload: Partial<Item>[]
): Promise<Partial<Item>[]>;
export async function processValues(
operation: Operation,
collection: string,
payload: Partial<Item> | Partial<Item>[]
) => {
let processedPayload = clone(payload);
if (Array.isArray(payload) === false) {
processedPayload = [processedPayload];
}
): Promise<Partial<Item> | Partial<Item>[]> {
const processedPayload = Array.isArray(payload) ? clone(payload) : [clone(payload)];
const specialFieldsInCollection = await database
.select('field', 'special')
@@ -82,7 +90,7 @@ export const processValues = async (
.whereNotNull('special');
await Promise.all(
processedPayload.map(async (record: any) => {
payload.map(async (record: any) => {
await Promise.all(
specialFieldsInCollection.map(async (field) => {
record[field.field] = await processField(field, record, operation);
@@ -91,26 +99,20 @@ export const processValues = async (
})
);
/** @TODO
*
* - Make config.ts file in root
* - Have it cache settings / env vars a la graphql/dataloader (memory-cache)
* - Have it have a function to reload env vars
*/
// Return the payload in it's original format
if (Array.isArray(payload) === false) {
return processedPayload[0];
if (Array.isArray(payload)) {
return processedPayload;
}
return processedPayload;
};
return processedPayload[0];
}
async function processField(
field: Pick<System, 'field' | 'special'>,
payload: Partial<Item>,
operation: Operation
) {
if (!field.special) return payload[field.field];
if (transformers.hasOwnProperty(field.special)) {
return await transformers[field.special](operation, payload[field.field], payload);
}

View File

@@ -74,7 +74,7 @@ export const processAST = async (
permissionsForCollections.find(
(permission) => permission.collection === collection
) === undefined
);
)!;
if (field) {
throw new ForbiddenException(
@@ -96,7 +96,9 @@ export const processAST = async (
/**
* Traverses the AST and returns an array of all collections that are being fetched
*/
function getCollectionsFromAST(ast: AST | NestedCollectionAST) {
function getCollectionsFromAST(
ast: AST | NestedCollectionAST
): { collection: string; field: string }[] {
const collections = [];
if (ast.type === 'collection') {
@@ -114,16 +116,19 @@ export const processAST = async (
}
}
return collections;
return collections as { collection: string; field: string }[];
}
function validateFields(ast: AST | NestedCollectionAST) {
if (ast.type === 'collection') {
const collection = ast.name;
// We check the availability of the permissions in the step before this is run
const permissions = permissionsForCollections.find(
(permission) => permission.collection === collection
);
const allowedFields = permissions.fields.split(',');
)!;
const allowedFields = permissions.fields?.split(',') || [];
for (const childAST of ast.children) {
if (childAST.type === 'collection') {
@@ -150,9 +155,10 @@ export const processAST = async (
if (ast.type === 'collection') {
const collection = ast.name;
// We check the availability of the permissions in the step before this is run
const permissions = permissionsForCollections.find(
(permission) => permission.collection === collection
);
)!;
ast.query = {
...ast.query,
@@ -162,7 +168,7 @@ export const processAST = async (
},
};
if (permissions.limit && ast.query.limit > permissions.limit) {
if (permissions.limit && ast.query.limit && ast.query.limit > permissions.limit) {
throw new ForbiddenException(
`You can't read more than ${permissions.limit} items at a time.`
);
@@ -194,7 +200,7 @@ export const processValues = async (
if (!permission) throw new ForbiddenException();
const allowedFields = permission.fields.split(',');
const allowedFields = permission.fields?.split(',') || [];
if (allowedFields.includes('*') === false) {
const keysInData = Object.keys(data);
@@ -229,7 +235,7 @@ export const checkAccess = async (
operation: Operation,
collection: string,
pk: string | number,
role: string
role: string | null
) => {
try {
const query: Query = {

View File

@@ -10,13 +10,13 @@ export const createUser = async (data: Partial<Item>, accountability: Accountabi
return await ItemsService.createItem('directus_users', data, accountability);
};
export const readUsers = async (query?: Query, accountability?: Accountability) => {
export const readUsers = async (query: Query, accountability?: Accountability) => {
return await ItemsService.readItems('directus_users', query, accountability);
};
export const readUser = async (
pk: string | number,
query?: Query,
query: Query,
accountability?: Accountability
) => {
return await ItemsService.readItem('directus_users', pk, query, accountability);
@@ -44,14 +44,14 @@ export const inviteUser = async (email: string, role: string, accountability: Ac
await createUser({ email, role, status: 'invited' }, accountability);
const payload = { email };
const token = jwt.sign(payload, process.env.SECRET, { expiresIn: '7d' });
const token = jwt.sign(payload, process.env.SECRET as string, { expiresIn: '7d' });
const acceptURL = process.env.PUBLIC_URL + '/admin/accept-invite?token=' + token;
await sendInviteMail(email, acceptURL);
};
export const acceptInvite = async (token: string, password: string) => {
const { email } = jwt.verify(token, process.env.SECRET) as { email: string };
const { email } = jwt.verify(token, process.env.SECRET as string) as { email: string };
const user = await database
.select('id', 'status')
.from('directus_users')

View File

@@ -47,11 +47,14 @@ function registerDrivers(storage: StorageManager) {
for (const [key, value] of Object.entries(process.env)) {
if ((key.startsWith('STORAGE') && key.endsWith('DRIVER')) === false) continue;
if (usedDrivers.includes(value) === false) usedDrivers.push(value);
if (value && usedDrivers.includes(value) === false) usedDrivers.push(value);
}
usedDrivers.forEach((driver) => {
storage.registerDriver<Storage>(driver, getStorageDriver(driver));
const storageDriver = getStorageDriver(driver);
if (storageDriver) {
storage.registerDriver<Storage>(driver, storageDriver);
}
});
}

View File

@@ -1,6 +1,6 @@
export type Accountability = {
role: string;
user?: string;
role: string | null;
user?: string | null;
admin?: boolean;
ip?: string;

View File

@@ -10,12 +10,12 @@ export {};
declare global {
namespace Express {
export interface Request {
token: string;
user: string;
token: string | null;
user: string | null;
role: string | null;
collection: string;
admin: boolean;
collection?: string;
sanitizedQuery?: Query;
sanitizedQuery: Query;
single?: boolean;
permissions?: Permission;
}

View File

@@ -4,3 +4,5 @@
*/
export type Item = Record<string, any>;
export type PrimaryKey = string | number;

View File

@@ -16,7 +16,7 @@ import database from '../database';
export default async function getASTFromQuery(
collection: string,
query: Query,
accountability: Accountability | null,
accountability?: Accountability,
operation?: Operation
): Promise<AST> {
/**
@@ -108,7 +108,7 @@ export default async function getASTFromQuery(
function parseFields(parentCollection: string, fields: string[]) {
fields = convertWildcards(parentCollection, fields);
if (!fields) return null;
if (!fields) return [];
const children: (NestedCollectionAST | FieldAST)[] = [];
@@ -132,13 +132,19 @@ export default async function getASTFromQuery(
for (const [relationalField, nestedFields] of Object.entries(relationalStructure)) {
const relatedCollection = getRelatedCollection(parentCollection, relationalField);
if (!relatedCollection) continue;
const relation = getRelation(parentCollection, relationalField);
if (!relation) continue;
const child: NestedCollectionAST = {
type: 'collection',
name: relatedCollection,
fieldKey: relationalField,
parentKey: 'id' /** @todo this needs to come from somewhere real */,
relation: getRelation(parentCollection, relationalField),
query: {} /** @todo inject nested query here */,
relation: relation,
query: {} /** @todo inject nested query here: ?deep[foo]=bar */,
children: parseFields(relatedCollection, nestedFields).filter(
filterEmptyChildCollections
),
@@ -175,7 +181,7 @@ export default async function getASTFromQuery(
}
}
function filterEmptyChildCollections(childAST: NestedCollectionAST) {
function filterEmptyChildCollections(childAST: FieldAST | NestedCollectionAST) {
if (childAST.type === 'collection' && childAST.children.length === 0) return false;
return true;
}

View File

@@ -3,7 +3,7 @@ import { get } from 'lodash';
// The path in JSON to fetch the email address from the profile.
// Note: a lot of services use `email` as the path. We fall back to that as default, so no need to
// map it here
const profileMap = {};
const profileMap: Record<string, string> = {};
/**
* Extract the email address from a given user profile coming from a providers API

View File

@@ -2,9 +2,9 @@
* Reads the environment variables to construct the configuration object required by Grant
*/
export default function getGrantConfig() {
const enabledProviders = process.env.OAUTH_PROVIDERS.split(',').map((provider) =>
provider.trim()
);
const enabledProviders = (process.env.OAUTH_PROVIDERS as string)
.split(',')
.map((provider) => provider.trim());
const config: any = {
defaults: {

View File

@@ -16,7 +16,7 @@ const IPTC_ENTRY_MARKER = Buffer.from([0x1c, 0x02]);
export default function parseIPTC(buffer: Buffer) {
if (!Buffer.isBuffer(buffer)) return {};
let iptc = {};
let iptc: Record<string, any> = {};
let lastIptcEntryPos = buffer.indexOf(IPTC_ENTRY_MARKER);
while (lastIptcEntryPos !== -1) {
@@ -39,12 +39,14 @@ export default function parseIPTC(buffer: Buffer) {
let iptcBlockTypeId = IPTC_ENTRY_TYPES.get(iptcBlockType);
let iptcData = buffer.slice(iptcBlockDataPos, iptcBlockDataPos + iptcBlockSize).toString();
if (iptc[iptcBlockTypeId] == null) {
iptc[iptcBlockTypeId] = iptcData;
} else if (Array.isArray(iptc[iptcBlockTypeId])) {
iptc[iptcBlockTypeId].push(iptcData);
} else {
iptc[iptcBlockTypeId] = [iptc[iptcBlockTypeId], iptcData];
if (iptcBlockTypeId) {
if (iptc[iptcBlockTypeId] == null) {
iptc[iptcBlockTypeId] = iptcData;
} else if (Array.isArray(iptc[iptcBlockTypeId])) {
iptc[iptcBlockTypeId].push(iptcData);
} else {
iptc[iptcBlockTypeId] = [iptc[iptcBlockTypeId], iptcData];
}
}
}