chore: Update dependencies

This commit is contained in:
Joachim Van Herwegen 2021-06-29 11:29:38 +02:00
parent d01382d36e
commit 5edbbc1958
37 changed files with 2904 additions and 3617 deletions

View File

@ -6,6 +6,8 @@ module.exports = {
tsconfigRootDir: __dirname, tsconfigRootDir: __dirname,
project: [ './tsconfig.json', './test/tsconfig.json' ], project: [ './tsconfig.json', './test/tsconfig.json' ],
}, },
// Ignoring js files (such as this one) since they seem to conflict with rules that require typing info
ignorePatterns: [ '*.js' ],
globals: { globals: {
AsyncIterable: 'readonly', AsyncIterable: 'readonly',
NodeJS: 'readonly', NodeJS: 'readonly',
@ -49,6 +51,7 @@ module.exports = {
'class-methods-use-this': 'off', 'class-methods-use-this': 'off',
'comma-dangle': [ 'error', 'always-multiline' ], 'comma-dangle': [ 'error', 'always-multiline' ],
'dot-location': [ 'error', 'property' ], 'dot-location': [ 'error', 'property' ],
'eslint-comments/disable-enable-pair': 'off',
// Allow declaring overloads in TypeScript (https://eslint.org/docs/rules/func-style) // Allow declaring overloads in TypeScript (https://eslint.org/docs/rules/func-style)
'func-style': [ 'error', 'declaration' ], 'func-style': [ 'error', 'declaration' ],
'generator-star-spacing': [ 'error', 'after' ], 'generator-star-spacing': [ 'error', 'after' ],
@ -74,7 +77,8 @@ module.exports = {
'unicorn/catch-error-name': 'off', 'unicorn/catch-error-name': 'off',
'unicorn/import-index': 'off', 'unicorn/import-index': 'off',
'unicorn/import-style': 'off', 'unicorn/import-style': 'off',
// This prevents some functional programming paradigms // The next 2 some functional programming paradigms
'unicorn/no-array-callback-reference': 'off',
'unicorn/no-fn-reference-in-iterator': 'off', 'unicorn/no-fn-reference-in-iterator': 'off',
'unicorn/no-object-as-default-parameter': 'off', 'unicorn/no-object-as-default-parameter': 'off',
'unicorn/numeric-separators-style': 'off', 'unicorn/numeric-separators-style': 'off',

6173
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -82,90 +82,90 @@
"@types/arrayify-stream": "^1.0.0", "@types/arrayify-stream": "^1.0.0",
"@types/async-lock": "^1.1.2", "@types/async-lock": "^1.1.2",
"@types/bcrypt": "^5.0.0", "@types/bcrypt": "^5.0.0",
"@types/cors": "^2.8.9", "@types/cors": "^2.8.10",
"@types/end-of-stream": "^1.4.0", "@types/end-of-stream": "^1.4.0",
"@types/mime-types": "^2.1.0", "@types/mime-types": "^2.1.0",
"@types/n3": "^1.4.4", "@types/n3": "^1.10.0",
"@types/node": "^14.10.2", "@types/node": "^15.12.5",
"@types/nodemailer": "^6.4.0", "@types/nodemailer": "^6.4.2",
"@types/pump": "^1.1.0", "@types/pump": "^1.1.1",
"@types/punycode": "^2.1.0", "@types/punycode": "^2.1.0",
"@types/rdf-js": "^4.0.0", "@types/rdf-js": "^4.0.2",
"@types/rdfjs__fetch": "^2.0.2", "@types/rdfjs__fetch": "^2.0.3",
"@types/rdfjs__fetch-lite": "^2.0.2", "@types/rdfjs__fetch-lite": "^2.0.3",
"@types/redis": "^2.8.28", "@types/redis": "^2.8.30",
"@types/redlock": "^4.0.1", "@types/redlock": "^4.0.1",
"@types/sparqljs": "^3.1.0", "@types/sparqljs": "^3.1.2",
"@types/streamify-array": "^1.0.0", "@types/streamify-array": "^1.0.0",
"@types/url-join": "^4.0.0", "@types/url-join": "^4.0.0",
"@types/uuid": "^8.3.0", "@types/uuid": "^8.3.0",
"@types/ws": "^7.4.0", "@types/ws": "^7.4.5",
"@types/yargs": "^16.0.0", "@types/yargs": "^17.0.0",
"arrayify-stream": "^1.0.0", "arrayify-stream": "^1.0.0",
"async-lock": "^1.2.4", "async-lock": "^1.3.0",
"bcrypt": "^5.0.0", "bcrypt": "^5.0.1",
"componentsjs": "^4.1.0", "componentsjs": "^4.3.0",
"cors": "^2.8.5", "cors": "^2.8.5",
"ejs": "^3.1.5", "ejs": "^3.1.6",
"end-of-stream": "^1.4.4", "end-of-stream": "^1.4.4",
"escape-string-regexp": "^4.0.0", "escape-string-regexp": "^4.0.0",
"fetch-sparql-endpoint": "^2.0.0", "fetch-sparql-endpoint": "^2.0.1",
"handlebars": "^4.7.6", "handlebars": "^4.7.7",
"jose": "^3.11.6", "jose": "^3.11.6",
"mime-types": "^2.1.27", "mime-types": "^2.1.31",
"n3": "^1.8.0", "n3": "^1.10.0",
"nodemailer": "^6.4.17", "nodemailer": "^6.6.2",
"oidc-provider": "^6.29.8", "oidc-provider": "^6.31.1",
"pump": "^3.0.0", "pump": "^3.0.0",
"punycode": "^2.1.1", "punycode": "^2.1.1",
"rdf-parse": "^1.7.0", "rdf-parse": "^1.8.1",
"rdf-serialize": "^1.1.0", "rdf-serialize": "^1.1.0",
"redis": "^3.0.2", "redis": "^3.1.2",
"redlock": "^4.2.0", "redlock": "^4.2.0",
"sparqlalgebrajs": "^3.0.0", "sparqlalgebrajs": "^3.0.0",
"sparqljs": "^3.1.2", "sparqljs": "^3.4.2",
"streamify-array": "^1.0.1", "streamify-array": "^1.0.1",
"url-join": "^4.0.1", "url-join": "^4.0.1",
"uuid": "^8.3.0", "uuid": "^8.3.2",
"winston": "^3.3.3", "winston": "^3.3.3",
"winston-transport": "^4.4.0", "winston-transport": "^4.4.0",
"ws": "^7.4.0", "ws": "^7.5.1",
"yargs": "^16.0.0" "yargs": "^17.0.1"
}, },
"devDependencies": { "devDependencies": {
"@inrupt/solid-client-authn-node": "^1.8.1", "@inrupt/solid-client-authn-node": "^1.9.1",
"@microsoft/tsdoc-config": "^0.15.0", "@microsoft/tsdoc-config": "^0.15.2",
"@tsconfig/node12": "^1.0.7", "@tsconfig/node12": "^1.0.9",
"@types/cheerio": "^0.22.27", "@types/cheerio": "^0.22.29",
"@types/ejs": "^3.0.5", "@types/ejs": "^3.0.6",
"@types/jest": "^26.0.13", "@types/jest": "^26.0.23",
"@types/rimraf": "^3.0.0", "@types/rimraf": "^3.0.0",
"@types/set-cookie-parser": "^2.4.0", "@types/set-cookie-parser": "^2.4.0",
"@types/supertest": "^2.0.10", "@types/supertest": "^2.0.11",
"@typescript-eslint/eslint-plugin": "^4.1.1", "@typescript-eslint/eslint-plugin": "^4.28.1",
"@typescript-eslint/parser": "^4.1.1", "@typescript-eslint/parser": "^4.28.1",
"cheerio": "^1.0.0-rc.5", "cheerio": "^1.0.0-rc.10",
"componentsjs-generator": "^2.1.0", "componentsjs-generator": "^2.4.0",
"cross-fetch": "^3.0.6", "cross-fetch": "^3.1.4",
"eslint": "^7.9.0", "eslint": "^7.29.0",
"eslint-config-es": "^3.20.3", "eslint-config-es": "^3.20.3",
"eslint-import-resolver-typescript": "^2.3.0", "eslint-import-resolver-typescript": "^2.4.0",
"eslint-plugin-import": "^2.22.0", "eslint-plugin-import": "^2.23.4",
"eslint-plugin-jest": "^24.1.0", "eslint-plugin-jest": "^24.3.6",
"eslint-plugin-tsdoc": "^0.2.7", "eslint-plugin-tsdoc": "^0.2.14",
"eslint-plugin-unused-imports": "^1.0.0", "eslint-plugin-unused-imports": "^1.1.1",
"husky": "^4.2.5", "husky": "^4.3.8",
"jest": "^27.0.3", "jest": "^27.0.6",
"jest-rdf": "^1.5.0", "jest-rdf": "^1.6.0",
"manual-git-changelog": "^1.0.1", "manual-git-changelog": "^1.0.1",
"node-mocks-http": "^1.8.1", "node-mocks-http": "^1.10.1",
"nodemon": "^2.0.4", "nodemon": "^2.0.7",
"rimraf": "^3.0.2", "rimraf": "^3.0.2",
"set-cookie-parser": "^2.4.8", "set-cookie-parser": "^2.4.8",
"stream-to-string": "^1.1.0", "stream-to-string": "^1.2.0",
"supertest": "^6.0.0", "supertest": "^6.1.3",
"ts-jest": "^27.0.2", "ts-jest": "^27.0.3",
"typedoc": "^0.21.0", "typedoc": "^0.21.2",
"typescript": "^4.0.2" "typescript": "^4.3.4"
} }
} }

View File

@ -30,7 +30,7 @@ export class BearerWebIdExtractor extends CredentialsExtractor {
const { headers: { authorization }} = request; const { headers: { authorization }} = request;
try { try {
const { webid: webId } = await this.verify(authorization as string); const { webid: webId } = await this.verify(authorization!);
this.logger.info(`Verified WebID via Bearer access token: ${webId}`); this.logger.info(`Verified WebID via Bearer access token: ${webId}`);
return { webId }; return { webId };
} catch (error: unknown) { } catch (error: unknown) {

View File

@ -45,7 +45,7 @@ export class DPoPWebIdExtractor extends CredentialsExtractor {
// and extract the WebID provided by the client // and extract the WebID provided by the client
try { try {
const { webid: webId } = await this.verify( const { webid: webId } = await this.verify(
authorization as string, authorization!,
{ {
header: dpop as string, header: dpop as string,
method: method as RequestMethod, method: method as RequestMethod,

View File

@ -18,7 +18,7 @@ export class UnsecureWebIdExtractor extends CredentialsExtractor {
} }
public async handle({ headers }: HttpRequest): Promise<Credentials> { public async handle({ headers }: HttpRequest): Promise<Credentials> {
const webId = /^WebID\s+(.*)/u.exec(headers.authorization as string)![1]; const webId = /^WebID\s+(.*)/u.exec(headers.authorization!)![1];
this.logger.info(`Agent unsecurely claims to be ${webId}`); this.logger.info(`Agent unsecurely claims to be ${webId}`);
return { webId }; return { webId };
} }

View File

@ -46,6 +46,8 @@ export class KeyConfigurationFactory implements ConfigurationFactory {
// If they are not, generate and save them // If they are not, generate and save them
const { privateKey } = await generateKeyPair('RS256'); const { privateKey } = await generateKeyPair('RS256');
const jwk = await fromKeyLike(privateKey); const jwk = await fromKeyLike(privateKey);
// Required for Solid authn client
jwk.alg = 'RS256';
// In node v15.12.0 the JWKS does not get accepted because the JWK is not a plain object, // In node v15.12.0 the JWKS does not get accepted because the JWK is not a plain object,
// which is why we convert it into a plain object here. // which is why we convert it into a plain object here.
// Potentially this can be changed at a later point in time to `{ keys: [ jwk ]}`. // Potentially this can be changed at a later point in time to `{ keys: [ jwk ]}`.

View File

@ -19,6 +19,6 @@ export class SessionHttpHandler extends InteractionHttpHandler {
if (!details.session || !details.session.accountId) { if (!details.session || !details.session.accountId) {
throw new NotImplementedHttpError('Only confirm actions with a session and accountId are supported'); throw new NotImplementedHttpError('Only confirm actions with a session and accountId are supported');
} }
await this.interactionCompleter.handleSafe({ ...input, webId: details.session.accountId }); await this.interactionCompleter.handleSafe({ ...input, webId: details.session.accountId as any });
} }
} }

View File

@ -188,16 +188,16 @@ export class RegistrationHandler extends HttpHandler {
* Verifies that all the data combinations make sense. * Verifies that all the data combinations make sense.
*/ */
private validateInput(parsed: NodeJS.Dict<string>): ParseResult { private validateInput(parsed: NodeJS.Dict<string>): ParseResult {
const { email, password, confirmPassword, podName, webId } = parsed; const { email, password, confirmPassword, podName, webId, createWebId, register, createPod } = parsed;
assert(typeof email === 'string' && email.length > 0 && emailRegex.test(email), assert(typeof email === 'string' && email.length > 0 && emailRegex.test(email),
'A valid e-mail address is required'); 'A valid e-mail address is required');
const result: ParseResult = { const result: ParseResult = {
email, email,
createWebId: Boolean(parsed.createWebId), createWebId: Boolean(createWebId),
register: Boolean(parsed.register), register: Boolean(register),
createPod: Boolean(parsed.createPod), createPod: Boolean(createPod),
data: parsed, data: parsed,
}; };

View File

@ -54,7 +54,7 @@ export class ExpiringAdapter implements Adapter {
if (payload.grantId) { if (payload.grantId) {
storagePromises.push( storagePromises.push(
(async(): Promise<void> => { (async(): Promise<void> => {
const grantKey = this.grantKeyFor(payload.grantId as string); const grantKey = this.grantKeyFor(payload.grantId!);
const grants = (await this.storage.get(grantKey) || []) as string[]; const grants = (await this.storage.get(grantKey) || []) as string[];
grants.push(key); grants.push(key);
await this.storage.set(grantKey, grants, expires); await this.storage.set(grantKey, grants, expires);

View File

@ -200,6 +200,7 @@ export * from './server/BaseHttpServerFactory';
export * from './server/HttpHandler'; export * from './server/HttpHandler';
export * from './server/HttpRequest'; export * from './server/HttpRequest';
export * from './server/HttpResponse'; export * from './server/HttpResponse';
export * from './server/HttpServerFactory';
export * from './server/WebSocketServerFactory'; export * from './server/WebSocketServerFactory';
export * from './server/WebSocketHandler'; export * from './server/WebSocketHandler';

View File

@ -7,6 +7,7 @@ import yargs from 'yargs';
import { getLoggerFor } from '../logging/LogUtil'; import { getLoggerFor } from '../logging/LogUtil';
import { absoluteFilePath, ensureTrailingSlash, joinFilePath } from '../util/PathUtil'; import { absoluteFilePath, ensureTrailingSlash, joinFilePath } from '../util/PathUtil';
import type { App } from './App'; import type { App } from './App';
export class AppRunner { export class AppRunner {
private readonly logger = getLoggerFor(this); private readonly logger = getLoggerFor(this);
@ -56,7 +57,8 @@ export class AppRunner {
stderr?: WriteStream; stderr?: WriteStream;
} = {}): void { } = {}): void {
// Parse the command-line arguments // Parse the command-line arguments
const { argv: params } = yargs(argv.slice(2)) // eslint-disable-next-line no-sync
const params = yargs(argv.slice(2))
.strict() .strict()
.usage('node ./bin/server.js [args]') .usage('node ./bin/server.js [args]')
.check((args): boolean => { .check((args): boolean => {
@ -84,7 +86,7 @@ export class AppRunner {
sparqlEndpoint: { type: 'string', alias: 's', requiresArg: true }, sparqlEndpoint: { type: 'string', alias: 's', requiresArg: true },
podConfigJson: { type: 'string', default: './pod-config.json', requiresArg: true }, podConfigJson: { type: 'string', default: './pod-config.json', requiresArg: true },
}) })
.help(); .parseSync();
// Gather settings for instantiating the server // Gather settings for instantiating the server
const loaderProperties: IComponentsManagerBuilderOptions<App> = { const loaderProperties: IComponentsManagerBuilderOptions<App> = {

View File

@ -207,12 +207,10 @@ export class DataAccessorBasedStore implements ResourceStore {
// if it contains no resources. If the container contains resources, // if it contains no resources. If the container contains resources,
// the server MUST respond with the 409 status code and response body describing the error." // the server MUST respond with the 409 status code and response body describing the error."
// https://solid.github.io/specification/protocol#deleting-resources // https://solid.github.io/specification/protocol#deleting-resources
if (isContainerIdentifier(identifier)) { // Auxiliary resources are not counted when deleting a container since they will also be deleted.
// Auxiliary resources are not counted when deleting a container since they will also be deleted if (isContainerIdentifier(identifier) && await this.hasProperChildren(identifier)) {
if (await this.hasProperChildren(identifier)) {
throw new ConflictHttpError('Can only delete empty containers.'); throw new ConflictHttpError('Can only delete empty containers.');
} }
}
// Solid, §5.4: "When a contained resource is deleted, the server MUST also delete the associated auxiliary // Solid, §5.4: "When a contained resource is deleted, the server MUST also delete the associated auxiliary
// resources" // resources"
// https://solid.github.io/specification/protocol#deleting-resources // https://solid.github.io/specification/protocol#deleting-resources
@ -291,9 +289,8 @@ export class DataAccessorBasedStore implements ResourceStore {
createContainers?: boolean): Promise<ResourceIdentifier[]> { createContainers?: boolean): Promise<ResourceIdentifier[]> {
// Make sure the metadata has the correct identifier and correct type quads // Make sure the metadata has the correct identifier and correct type quads
// Need to do this before handling container data to have the correct identifier // Need to do this before handling container data to have the correct identifier
const { metadata } = representation; representation.metadata.identifier = DataFactory.namedNode(identifier.path);
metadata.identifier = DataFactory.namedNode(identifier.path); addResourceMetadata(representation.metadata, isContainer);
addResourceMetadata(metadata, isContainer);
// Validate container data // Validate container data
if (isContainer) { if (isContainer) {

View File

@ -142,8 +142,8 @@ export class ChainedConverter extends RepresentationConverter {
return input.representation; return input.representation;
} }
const { path } = match; const { path, inType, outType } = match;
this.logger.debug(`Converting ${match.inType} -> ${[ ...path.intermediateTypes, match.outType ].join(' -> ')}.`); this.logger.debug(`Converting ${inType} -> ${[ ...path.intermediateTypes, outType ].join(' -> ')}.`);
const args = { ...input }; const args = { ...input };
for (let i = 0; i < path.converters.length - 1; ++i) { for (let i = 0; i < path.converters.length - 1; ++i) {
@ -152,7 +152,7 @@ export class ChainedConverter extends RepresentationConverter {
args.representation = await path.converters[i].handle(args); args.representation = await path.converters[i].handle(args);
} }
// For the last converter we set the preferences to the best output type // For the last converter we set the preferences to the best output type
args.preferences = { type: { [match.outType]: 1 }}; args.preferences = { type: { [outType]: 1 }};
return path.converters.slice(-1)[0].handle(args); return path.converters.slice(-1)[0].handle(args);
} }

View File

@ -44,7 +44,7 @@ export class IfNeededConverter extends RepresentationConverter {
const noMatchingMediaType = !matchesMediaPreferences(contentType, preferences.type); const noMatchingMediaType = !matchesMediaPreferences(contentType, preferences.type);
if (noMatchingMediaType) { if (noMatchingMediaType) {
this.logger.debug(`Conversion needed for ${identifier this.logger.debug(`Conversion needed for ${identifier
.path} from ${representation.metadata.contentType} to satisfy ${!preferences.type ? .path} from ${contentType} to satisfy ${!preferences.type ?
'""' : '""' :
Object.entries(preferences.type).map(([ value, weight ]): string => `${value};q=${weight}`).join(', ')}`); Object.entries(preferences.type).map(([ value, weight ]): string => `${value};q=${weight}`).join(', ')}`);
} }

View File

@ -142,6 +142,6 @@ export class SparqlUpdatePatchHandler extends ConvertingPatchHandler {
this.logger.debug(`${result.size} quads will be stored to ${identifier.path}.`); this.logger.debug(`${result.size} quads will be stored to ${identifier.path}.`);
return new BasicRepresentation(result.match() as Readable, metadata); return new BasicRepresentation(result.match() as unknown as Readable, metadata);
} }
} }

View File

@ -39,7 +39,7 @@ export class ConvertingRouterRule extends RouterRule {
entry.supportChecker.supports({ identifier, representation })); entry.supportChecker.supports({ identifier, representation }));
} else { } else {
// No content-type given so we can only check if one of the stores has data for the identifier // No content-type given so we can only check if one of the stores has data for the identifier
store = await this.findStore(async(entry): Promise<boolean> => entry.store.resourceExists(input.identifier)); store = await this.findStore(async(entry): Promise<boolean> => entry.store.resourceExists(identifier));
} }
return store; return store;
} }

View File

@ -144,7 +144,7 @@ export function isContainerIdentifier(identifier: ResourceIdentifier): boolean {
* E.g., `http://test.com/` results in `{ scheme: 'http://', rest: 'test.com/' }`. * E.g., `http://test.com/` results in `{ scheme: 'http://', rest: 'test.com/' }`.
* @param url - String to parse. * @param url - String to parse.
*/ */
export function extractScheme(url: string): { scheme: string; rest: string} { export function extractScheme(url: string): { scheme: string; rest: string } {
const match = /^([^:]+:\/\/)(.*)$/u.exec(url)!; const match = /^([^:]+:\/\/)(.*)$/u.exec(url)!;
return { scheme: match[1], rest: match[2] }; return { scheme: match[1], rest: match[2] };
} }

View File

@ -1,4 +1,4 @@
/* eslint-disable @typescript-eslint/naming-convention, function-paren-newline */ /* eslint-disable function-paren-newline */
import { namedNode } from '@rdfjs/data-model'; import { namedNode } from '@rdfjs/data-model';
import type { NamedNode } from 'rdf-js'; import type { NamedNode } from 'rdf-js';

View File

@ -37,7 +37,6 @@ export class IdentityTestState {
* @param body - Body to send along. * @param body - Body to send along.
* @param contentType - Content-Type of the body. * @param contentType - Content-Type of the body.
*/ */
// eslint-disable-next-line default-param-last
public async fetchIdp(url: string, method = 'GET', body?: string, contentType?: string): Promise<Response> { public async fetchIdp(url: string, method = 'GET', body?: string, contentType?: string): Promise<Response> {
const options = { method, headers: { cookie: this.cookie }, body, redirect: 'manual' } as any; const options = { method, headers: { cookie: this.cookie }, body, redirect: 'manual' } as any;
if (contentType) { if (contentType) {

View File

@ -1,11 +1,12 @@
import { createResponse } from 'node-mocks-http'; import { createResponse } from 'node-mocks-http';
import { ConstantMetadataWriter } from '../../../../../src/ldp/http/metadata/ConstantMetadataWriter'; import { ConstantMetadataWriter } from '../../../../../src/ldp/http/metadata/ConstantMetadataWriter';
import type { HttpResponse } from '../../../../../src/server/HttpResponse';
describe('A ConstantMetadataWriter', (): void => { describe('A ConstantMetadataWriter', (): void => {
const writer = new ConstantMetadataWriter({ 'custom-Header': 'X', other: 'Y' }); const writer = new ConstantMetadataWriter({ 'custom-Header': 'X', other: 'Y' });
it('adds new headers.', async(): Promise<void> => { it('adds new headers.', async(): Promise<void> => {
const response = createResponse(); const response = createResponse() as HttpResponse;
await expect(writer.handle({ response })).resolves.toBeUndefined(); await expect(writer.handle({ response })).resolves.toBeUndefined();
@ -13,7 +14,7 @@ describe('A ConstantMetadataWriter', (): void => {
}); });
it('extends existing headers.', async(): Promise<void> => { it('extends existing headers.', async(): Promise<void> => {
const response = createResponse(); const response = createResponse() as HttpResponse;
response.setHeader('Other', 'A'); response.setHeader('Other', 'A');
await expect(writer.handle({ response })).resolves.toBeUndefined(); await expect(writer.handle({ response })).resolves.toBeUndefined();

View File

@ -1,13 +1,14 @@
import { createResponse } from 'node-mocks-http'; import { createResponse } from 'node-mocks-http';
import { LinkRelMetadataWriter } from '../../../../../src/ldp/http/metadata/LinkRelMetadataWriter'; import { LinkRelMetadataWriter } from '../../../../../src/ldp/http/metadata/LinkRelMetadataWriter';
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata'; import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
import type { HttpResponse } from '../../../../../src/server/HttpResponse';
import { LDP, RDF } from '../../../../../src/util/Vocabularies'; import { LDP, RDF } from '../../../../../src/util/Vocabularies';
describe('A LinkRelMetadataWriter', (): void => { describe('A LinkRelMetadataWriter', (): void => {
const writer = new LinkRelMetadataWriter({ [RDF.type]: 'type', dummy: 'dummy' }); const writer = new LinkRelMetadataWriter({ [RDF.type]: 'type', dummy: 'dummy' });
it('adds the correct link headers.', async(): Promise<void> => { it('adds the correct link headers.', async(): Promise<void> => {
const response = createResponse(); const response = createResponse() as HttpResponse;
const metadata = new RepresentationMetadata({ [RDF.type]: LDP.terms.Resource, unused: 'text' }); const metadata = new RepresentationMetadata({ [RDF.type]: LDP.terms.Resource, unused: 'text' });
await expect(writer.handle({ response, metadata })).resolves.toBeUndefined(); await expect(writer.handle({ response, metadata })).resolves.toBeUndefined();
expect(response.getHeaders()).toEqual({ link: `<${LDP.Resource}>; rel="type"` }); expect(response.getHeaders()).toEqual({ link: `<${LDP.Resource}>; rel="type"` });

View File

@ -1,13 +1,14 @@
import { createResponse } from 'node-mocks-http'; import { createResponse } from 'node-mocks-http';
import { MappedMetadataWriter } from '../../../../../src/ldp/http/metadata/MappedMetadataWriter'; import { MappedMetadataWriter } from '../../../../../src/ldp/http/metadata/MappedMetadataWriter';
import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata'; import { RepresentationMetadata } from '../../../../../src/ldp/representation/RepresentationMetadata';
import type { HttpResponse } from '../../../../../src/server/HttpResponse';
import { CONTENT_TYPE } from '../../../../../src/util/Vocabularies'; import { CONTENT_TYPE } from '../../../../../src/util/Vocabularies';
describe('A MappedMetadataWriter', (): void => { describe('A MappedMetadataWriter', (): void => {
const writer = new MappedMetadataWriter({ [CONTENT_TYPE]: 'content-type', dummy: 'dummy' }); const writer = new MappedMetadataWriter({ [CONTENT_TYPE]: 'content-type', dummy: 'dummy' });
it('adds metadata to the corresponding header.', async(): Promise<void> => { it('adds metadata to the corresponding header.', async(): Promise<void> => {
const response = createResponse(); const response = createResponse() as HttpResponse;
const metadata = new RepresentationMetadata({ [CONTENT_TYPE]: 'text/turtle', unused: 'text' }); const metadata = new RepresentationMetadata({ [CONTENT_TYPE]: 'text/turtle', unused: 'text' });
await expect(writer.handle({ response, metadata })).resolves.toBeUndefined(); await expect(writer.handle({ response, metadata })).resolves.toBeUndefined();
expect(response.getHeaders()).toEqual({ 'content-type': 'text/turtle' }); expect(response.getHeaders()).toEqual({ 'content-type': 'text/turtle' });

View File

@ -9,7 +9,7 @@ describe('A WacAllowMetadataWriter', (): void => {
let response: HttpResponse; let response: HttpResponse;
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
response = createResponse(); response = createResponse() as HttpResponse;
}); });
it('adds no header if there is no relevant metadata.', async(): Promise<void> => { it('adds no header if there is no relevant metadata.', async(): Promise<void> => {

View File

@ -10,7 +10,7 @@ describe('A WwwAuthMetadataWriter', (): void => {
let response: HttpResponse; let response: HttpResponse;
beforeEach(async(): Promise<void> => { beforeEach(async(): Promise<void> => {
response = createResponse(); response = createResponse() as HttpResponse;
}); });
it('adds no header if there is no relevant metadata.', async(): Promise<void> => { it('adds no header if there is no relevant metadata.', async(): Promise<void> => {

View File

@ -112,8 +112,8 @@ describe('A RepresentationMetadata', (): void => {
metadata.setMetadata(other); metadata.setMetadata(other);
expect(metadata.identifier).toEqual(other.identifier); expect(metadata.identifier).toEqual(other.identifier);
expect(metadata.quads()).toBeRdfIsomorphic(inputQuads.concat([ expect(metadata.quads()).toBeRdfIsomorphic([ ...inputQuads,
quad(identifier, namedNode('test:pred'), literal('objVal')) ])); quad(identifier, namedNode('test:pred'), literal('objVal')) ]);
}); });
it('updates its identifier when copying metadata.', async(): Promise<void> => { it('updates its identifier when copying metadata.', async(): Promise<void> => {
@ -134,7 +134,7 @@ describe('A RepresentationMetadata', (): void => {
quad(namedNode('random'), namedNode('new'), namedNode('triple')), quad(namedNode('random'), namedNode('new'), namedNode('triple')),
]; ];
metadata.addQuads(newQuads); metadata.addQuads(newQuads);
expect(metadata.quads()).toBeRdfIsomorphic(newQuads.concat(inputQuads)); expect(metadata.quads()).toBeRdfIsomorphic([ ...newQuads, ...inputQuads ]);
}); });
it('can remove quads.', async(): Promise<void> => { it('can remove quads.', async(): Promise<void> => {
@ -145,13 +145,13 @@ describe('A RepresentationMetadata', (): void => {
it('can add a single value for a predicate.', async(): Promise<void> => { it('can add a single value for a predicate.', async(): Promise<void> => {
const newQuad = quad(identifier, namedNode('new'), namedNode('triple')); const newQuad = quad(identifier, namedNode('new'), namedNode('triple'));
metadata.add(newQuad.predicate as NamedNode, newQuad.object as NamedNode); metadata.add(newQuad.predicate as NamedNode, newQuad.object as NamedNode);
expect(metadata.quads()).toBeRdfIsomorphic([ newQuad ].concat(inputQuads)); expect(metadata.quads()).toBeRdfIsomorphic([ newQuad, ...inputQuads ]);
}); });
it('can add single values as string.', async(): Promise<void> => { it('can add single values as string.', async(): Promise<void> => {
const newQuad = quad(identifier, namedNode('new'), literal('triple')); const newQuad = quad(identifier, namedNode('new'), literal('triple'));
metadata.add(newQuad.predicate as NamedNode, newQuad.object.value); metadata.add(newQuad.predicate as NamedNode, newQuad.object.value);
expect(metadata.quads()).toBeRdfIsomorphic([ newQuad ].concat(inputQuads)); expect(metadata.quads()).toBeRdfIsomorphic([ newQuad, ...inputQuads ]);
}); });
it('can add multiple values for a predicate.', async(): Promise<void> => { it('can add multiple values for a predicate.', async(): Promise<void> => {
@ -160,7 +160,7 @@ describe('A RepresentationMetadata', (): void => {
quad(identifier, namedNode('new'), namedNode('triple2')), quad(identifier, namedNode('new'), namedNode('triple2')),
]; ];
metadata.add(namedNode('new'), [ namedNode('triple'), namedNode('triple2') ]); metadata.add(namedNode('new'), [ namedNode('triple'), namedNode('triple2') ]);
expect(metadata.quads()).toBeRdfIsomorphic(newQuads.concat(inputQuads)); expect(metadata.quads()).toBeRdfIsomorphic([ ...newQuads, ...inputQuads ]);
}); });
it('can remove a single value for a predicate.', async(): Promise<void> => { it('can remove a single value for a predicate.', async(): Promise<void> => {

View File

@ -1,4 +1,5 @@
import { createRequest, createResponse } from 'node-mocks-http'; import { createRequest, createResponse } from 'node-mocks-http';
import type { HttpResponse } from '../../../../src/server/HttpResponse';
import { CorsHandler } from '../../../../src/server/middleware/CorsHandler'; import { CorsHandler } from '../../../../src/server/middleware/CorsHandler';
import { guardStream } from '../../../../src/util/GuardedStream'; import { guardStream } from '../../../../src/util/GuardedStream';
@ -7,7 +8,7 @@ describe('a CorsHandler', (): void => {
const handler = new CorsHandler(); const handler = new CorsHandler();
const request = guardStream(createRequest()); const request = guardStream(createRequest());
const response = createResponse(); const response = createResponse() as HttpResponse;
await handler.handleSafe({ request, response }); await handler.handleSafe({ request, response });
expect(response.getHeaders()).toEqual(expect.objectContaining({ expect(response.getHeaders()).toEqual(expect.objectContaining({
@ -23,7 +24,7 @@ describe('a CorsHandler', (): void => {
origin: 'example.org', origin: 'example.org',
}, },
})); }));
const response = createResponse(); const response = createResponse() as HttpResponse;
await handler.handleSafe({ request, response }); await handler.handleSafe({ request, response });
expect(response.getHeaders()).toEqual(expect.objectContaining({ expect(response.getHeaders()).toEqual(expect.objectContaining({
@ -37,7 +38,7 @@ describe('a CorsHandler', (): void => {
}); });
const request = guardStream(createRequest()); const request = guardStream(createRequest());
const response = createResponse(); const response = createResponse() as HttpResponse;
await handler.handleSafe({ request, response }); await handler.handleSafe({ request, response });
expect(response.getHeaders()).toEqual(expect.objectContaining({ expect(response.getHeaders()).toEqual(expect.objectContaining({

View File

@ -1,4 +1,5 @@
import { createRequest, createResponse } from 'node-mocks-http'; import { createRequest, createResponse } from 'node-mocks-http';
import type { HttpResponse } from '../../../../src/server/HttpResponse';
import { HeaderHandler } from '../../../../src/server/middleware/HeaderHandler'; import { HeaderHandler } from '../../../../src/server/middleware/HeaderHandler';
import { guardStream } from '../../../../src/util/GuardedStream'; import { guardStream } from '../../../../src/util/GuardedStream';
@ -8,7 +9,7 @@ describe('a HeaderHandler', (): void => {
const handler = new HeaderHandler(headers); const handler = new HeaderHandler(headers);
const request = guardStream(createRequest()); const request = guardStream(createRequest());
const response = createResponse(); const response = createResponse() as HttpResponse;
await handler.handleSafe({ request, response }); await handler.handleSafe({ request, response });
expect(response.getHeaders()).toEqual(expect.objectContaining(headers)); expect(response.getHeaders()).toEqual(expect.objectContaining(headers));

View File

@ -122,7 +122,7 @@ describe('A StaticAssetHandler', (): void => {
it('throws a 404 when the asset does not exist.', async(): Promise<void> => { it('throws a 404 when the asset does not exist.', async(): Promise<void> => {
const request = { method: 'GET', url: '/foo/bar/main' }; const request = { method: 'GET', url: '/foo/bar/main' };
const response = createResponse({ eventEmitter: EventEmitter }); const response = createResponse({ eventEmitter: EventEmitter });
const error = new Error() as SystemError; const error = new Error('no file') as SystemError;
error.code = 'ENOENT'; error.code = 'ENOENT';
const stream = new PassThrough(); const stream = new PassThrough();
stream._read = (): any => stream.emit('error', error); stream._read = (): any => stream.emit('error', error);
@ -135,7 +135,7 @@ describe('A StaticAssetHandler', (): void => {
it('throws a 404 when the asset is folder.', async(): Promise<void> => { it('throws a 404 when the asset is folder.', async(): Promise<void> => {
const request = { method: 'GET', url: '/foo/bar/main' }; const request = { method: 'GET', url: '/foo/bar/main' };
const response = createResponse({ eventEmitter: EventEmitter }); const response = createResponse({ eventEmitter: EventEmitter });
const error = new Error() as SystemError; const error = new Error('is directory') as SystemError;
error.code = 'EISDIR'; error.code = 'EISDIR';
const stream = new PassThrough(); const stream = new PassThrough();
stream._read = (): any => stream.emit('error', error); stream._read = (): any => stream.emit('error', error);
@ -149,7 +149,7 @@ describe('A StaticAssetHandler', (): void => {
const request = { method: 'GET', url: '/foo/bar/main' }; const request = { method: 'GET', url: '/foo/bar/main' };
const response = createResponse({ eventEmitter: EventEmitter }); const response = createResponse({ eventEmitter: EventEmitter });
const responseEnd = new Promise((resolve): any => response.on('end', resolve)); const responseEnd = new Promise((resolve): any => response.on('end', resolve));
const error = new Error(); const error = new Error('random error');
const stream = new PassThrough(); const stream = new PassThrough();
stream._read = (): any => stream.emit('error', error); stream._read = (): any => stream.emit('error', error);
createReadStream.mockReturnValueOnce(stream as any); createReadStream.mockReturnValueOnce(stream as any);

View File

@ -1,31 +1,32 @@
import { createResponse } from 'node-mocks-http'; import { createResponse } from 'node-mocks-http';
import type { HttpResponse } from '../../../../src/server/HttpResponse';
import { WebSocketAdvertiser } from '../../../../src/server/middleware/WebSocketAdvertiser'; import { WebSocketAdvertiser } from '../../../../src/server/middleware/WebSocketAdvertiser';
describe('A WebSocketAdvertiser', (): void => { describe('A WebSocketAdvertiser', (): void => {
it('writes a ws: socket when given an http: URL.', async(): Promise<void> => { it('writes a ws: socket when given an http: URL.', async(): Promise<void> => {
const writer = new WebSocketAdvertiser('http://test.example/'); const writer = new WebSocketAdvertiser('http://test.example/');
const response = createResponse(); const response = createResponse() as HttpResponse;
await writer.handle({ response } as any); await writer.handle({ response } as any);
expect(response.getHeaders()).toEqual({ 'updates-via': 'ws://test.example/' }); expect(response.getHeaders()).toEqual({ 'updates-via': 'ws://test.example/' });
}); });
it('writes a ws: socket when given a ws: URL.', async(): Promise<void> => { it('writes a ws: socket when given a ws: URL.', async(): Promise<void> => {
const writer = new WebSocketAdvertiser('ws://test.example/'); const writer = new WebSocketAdvertiser('ws://test.example/');
const response = createResponse(); const response = createResponse() as HttpResponse;
await writer.handle({ response } as any); await writer.handle({ response } as any);
expect(response.getHeaders()).toEqual({ 'updates-via': 'ws://test.example/' }); expect(response.getHeaders()).toEqual({ 'updates-via': 'ws://test.example/' });
}); });
it('writes a wss: socket when given an https: URL.', async(): Promise<void> => { it('writes a wss: socket when given an https: URL.', async(): Promise<void> => {
const writer = new WebSocketAdvertiser('https://test.example/'); const writer = new WebSocketAdvertiser('https://test.example/');
const response = createResponse(); const response = createResponse() as HttpResponse;
await writer.handle({ response } as any); await writer.handle({ response } as any);
expect(response.getHeaders()).toEqual({ 'updates-via': 'wss://test.example/' }); expect(response.getHeaders()).toEqual({ 'updates-via': 'wss://test.example/' });
}); });
it('writes a wss: socket when given a wss: URL.', async(): Promise<void> => { it('writes a wss: socket when given a wss: URL.', async(): Promise<void> => {
const writer = new WebSocketAdvertiser('wss://test.example/'); const writer = new WebSocketAdvertiser('wss://test.example/');
const response = createResponse(); const response = createResponse() as HttpResponse;
await writer.handle({ response } as any); await writer.handle({ response } as any);
expect(response.getHeaders()).toEqual({ 'updates-via': 'wss://test.example/' }); expect(response.getHeaders()).toEqual({ 'updates-via': 'wss://test.example/' });
}); });

View File

@ -9,7 +9,7 @@ describe('RenderEjsHandler', (): void => {
let templateFile: string; let templateFile: string;
beforeEach((): void => { beforeEach((): void => {
response = createResponse(); response = createResponse() as HttpResponse;
templatePath = joinFilePath(__dirname, '../../../assets/idp'); templatePath = joinFilePath(__dirname, '../../../assets/idp');
templateFile = 'testHtml.ejs'; templateFile = 'testHtml.ejs';
}); });

View File

@ -15,7 +15,7 @@ describe('RouterHandler', (): void => {
genericRequest = guardStream(createRequest({ genericRequest = guardStream(createRequest({
url: '/test', url: '/test',
})); }));
genericResponse = createResponse(); genericResponse = createResponse() as HttpResponse;
genericInput = { genericInput = {
request: genericRequest, request: genericRequest,
response: genericResponse, response: genericResponse,

View File

@ -265,7 +265,7 @@ describe('A SparqlDataAccessor', (): void => {
fetchError = 'error'; fetchError = 'error';
await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toBe(fetchError); await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toBe(fetchError);
fetchError = new Error(); fetchError = new Error('read error');
await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toThrow(fetchError); await expect(accessor.getMetadata({ path: 'http://identifier' })).rejects.toThrow(fetchError);
fetchError = undefined; fetchError = undefined;
@ -278,7 +278,7 @@ describe('A SparqlDataAccessor', (): void => {
updateError = 'error'; updateError = 'error';
await expect(accessor.writeContainer(identifier, metadata)).rejects.toBe(updateError); await expect(accessor.writeContainer(identifier, metadata)).rejects.toBe(updateError);
updateError = new Error(); updateError = new Error('write error');
await expect(accessor.writeContainer(identifier, metadata)).rejects.toThrow(updateError); await expect(accessor.writeContainer(identifier, metadata)).rejects.toThrow(updateError);
updateError = undefined; updateError = undefined;

View File

@ -19,7 +19,7 @@ describe('An ErrorToQuadConverter', (): void => {
}); });
it('does not support multiple errors.', async(): Promise<void> => { it('does not support multiple errors.', async(): Promise<void> => {
const representation = new BasicRepresentation([ new Error(), new Error() ], 'internal/error', false); const representation = new BasicRepresentation([ new Error('a'), new Error('b') ], 'internal/error', false);
const prom = converter.handle({ identifier, representation, preferences }); const prom = converter.handle({ identifier, representation, preferences });
await expect(prom).rejects.toThrow('Only single errors are supported.'); await expect(prom).rejects.toThrow('Only single errors are supported.');
await expect(prom).rejects.toThrow(InternalServerError); await expect(prom).rejects.toThrow(InternalServerError);

View File

@ -32,7 +32,7 @@ describe('An ErrorToTemplateConverter', (): void => {
}); });
it('does not support multiple errors.', async(): Promise<void> => { it('does not support multiple errors.', async(): Promise<void> => {
const representation = new BasicRepresentation([ new Error(), new Error() ], 'internal/error', false); const representation = new BasicRepresentation([ new Error('a'), new Error('b') ], 'internal/error', false);
const prom = converter.handle({ identifier, representation, preferences }); const prom = converter.handle({ identifier, representation, preferences });
await expect(prom).rejects.toThrow('Only single errors are supported.'); await expect(prom).rejects.toThrow('Only single errors are supported.');
await expect(prom).rejects.toThrow(InternalServerError); await expect(prom).rejects.toThrow(InternalServerError);

View File

@ -105,10 +105,10 @@ describe('A SparqlUpdatePatchHandler', (): void => {
it('handles INSERT DATA updates.', async(): Promise<void> => { it('handles INSERT DATA updates.', async(): Promise<void> => {
await handle(fulfilledDataInsert); await handle(fulfilledDataInsert);
expect(await basicChecks(startQuads.concat( expect(await basicChecks([ ...startQuads,
[ quad(namedNode('http://test.com/s1'), namedNode('http://test.com/p1'), namedNode('http://test.com/o1')), quad(namedNode('http://test.com/s1'), namedNode('http://test.com/p1'), namedNode('http://test.com/o1')),
quad(namedNode('http://test.com/s2'), namedNode('http://test.com/p2'), namedNode('http://test.com/o2')) ], quad(namedNode('http://test.com/s2'), namedNode('http://test.com/p2'), namedNode('http://test.com/o2')),
))).toBe(true); ])).toBe(true);
}); });
it('handles DELETE DATA updates.', async(): Promise<void> => { it('handles DELETE DATA updates.', async(): Promise<void> => {

View File

@ -4,7 +4,6 @@ import { PassThrough } from 'stream';
import streamifyArray from 'streamify-array'; import streamifyArray from 'streamify-array';
import type { SystemError } from '../../src/util/errors/SystemError'; import type { SystemError } from '../../src/util/errors/SystemError';
/* eslint-disable @typescript-eslint/naming-convention */
const portNames = [ const portNames = [
// Integration // Integration
'DynamicPods', 'DynamicPods',