mirror of
https://github.com/CommunitySolidServer/CommunitySolidServer.git
synced 2024-10-03 14:55:10 +00:00
feat: Add ContentTypeReplacer to conversion chain
This commit is contained in:
parent
fa94c7d4bb
commit
fdd42bb7b3
@ -21,12 +21,12 @@
|
|||||||
"@type": "IfNeededConverter",
|
"@type": "IfNeededConverter",
|
||||||
"comment": "Only continue converting if the requester cannot accept the available content type"
|
"comment": "Only continue converting if the requester cannot accept the available content type"
|
||||||
},
|
},
|
||||||
{ "@id": "urn:solid-server:default:ContentTypeReplacer" },
|
|
||||||
{
|
{
|
||||||
"comment": "Automatically finds a path through a set of converters from one type to another.",
|
"comment": "Automatically finds a path through a set of converters from one type to another.",
|
||||||
"@id": "urn:solid-server:default:ChainedConverter",
|
"@id": "urn:solid-server:default:ChainedConverter",
|
||||||
"@type": "ChainedConverter",
|
"@type": "ChainedConverter",
|
||||||
"converters": [
|
"converters": [
|
||||||
|
{ "@id": "urn:solid-server:default:ContentTypeReplacer" },
|
||||||
{ "@id": "urn:solid-server:default:RdfToQuadConverter" },
|
{ "@id": "urn:solid-server:default:RdfToQuadConverter" },
|
||||||
{ "@id": "urn:solid-server:default:QuadToRdfConverter" },
|
{ "@id": "urn:solid-server:default:QuadToRdfConverter" },
|
||||||
{ "@id": "urn:solid-server:default:ContainerToTemplateConverter" },
|
{ "@id": "urn:solid-server:default:ContainerToTemplateConverter" },
|
||||||
|
@ -4,7 +4,7 @@ import type { ValuePreferences } from '../../http/representation/RepresentationP
|
|||||||
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
import { NotImplementedHttpError } from '../../util/errors/NotImplementedHttpError';
|
||||||
import { matchesMediaType, getConversionTarget } from './ConversionUtil';
|
import { matchesMediaType, getConversionTarget } from './ConversionUtil';
|
||||||
import type { RepresentationConverterArgs } from './RepresentationConverter';
|
import type { RepresentationConverterArgs } from './RepresentationConverter';
|
||||||
import { RepresentationConverter } from './RepresentationConverter';
|
import { TypedRepresentationConverter } from './TypedRepresentationConverter';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A {@link RepresentationConverter} that changes the content type
|
* A {@link RepresentationConverter} that changes the content type
|
||||||
@ -13,7 +13,7 @@ import { RepresentationConverter } from './RepresentationConverter';
|
|||||||
* Useful for when a content type is binary-compatible with another one;
|
* Useful for when a content type is binary-compatible with another one;
|
||||||
* for instance, all JSON-LD files are valid JSON files.
|
* for instance, all JSON-LD files are valid JSON files.
|
||||||
*/
|
*/
|
||||||
export class ContentTypeReplacer extends RepresentationConverter {
|
export class ContentTypeReplacer extends TypedRepresentationConverter {
|
||||||
private readonly contentTypeMap: Record<string, ValuePreferences> = {};
|
private readonly contentTypeMap: Record<string, ValuePreferences> = {};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -40,15 +40,22 @@ export class ContentTypeReplacer extends RepresentationConverter {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public async getOutputTypes(contentType: string): Promise<ValuePreferences> {
|
||||||
|
const supported = Object.keys(this.contentTypeMap)
|
||||||
|
.filter((type): boolean => matchesMediaType(contentType, type))
|
||||||
|
.map((type): ValuePreferences => this.contentTypeMap[type]);
|
||||||
|
return Object.assign({} as ValuePreferences, ...supported);
|
||||||
|
}
|
||||||
|
|
||||||
public async canHandle({ representation, preferences }: RepresentationConverterArgs): Promise<void> {
|
public async canHandle({ representation, preferences }: RepresentationConverterArgs): Promise<void> {
|
||||||
this.getReplacementType(representation.metadata.contentType, preferences.type);
|
await this.getReplacementType(representation.metadata.contentType, preferences.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Changes the content type on the representation.
|
* Changes the content type on the representation.
|
||||||
*/
|
*/
|
||||||
public async handle({ representation, preferences }: RepresentationConverterArgs): Promise<Representation> {
|
public async handle({ representation, preferences }: RepresentationConverterArgs): Promise<Representation> {
|
||||||
const contentType = this.getReplacementType(representation.metadata.contentType, preferences.type);
|
const contentType = await this.getReplacementType(representation.metadata.contentType, preferences.type);
|
||||||
const metadata = new RepresentationMetadata(representation.metadata, contentType);
|
const metadata = new RepresentationMetadata(representation.metadata, contentType);
|
||||||
return { ...representation, metadata };
|
return { ...representation, metadata };
|
||||||
}
|
}
|
||||||
@ -61,11 +68,9 @@ export class ContentTypeReplacer extends RepresentationConverter {
|
|||||||
* Find a replacement content type that matches the preferences,
|
* Find a replacement content type that matches the preferences,
|
||||||
* or throws an error if none was found.
|
* or throws an error if none was found.
|
||||||
*/
|
*/
|
||||||
private getReplacementType(contentType = 'unknown', preferred: ValuePreferences = {}): string {
|
private async getReplacementType(contentType = 'unknown', preferred: ValuePreferences = {}): Promise<string> {
|
||||||
const supported = Object.keys(this.contentTypeMap)
|
const supported = await this.getOutputTypes(contentType);
|
||||||
.filter((type): boolean => matchesMediaType(contentType, type))
|
const match = getConversionTarget(supported, preferred);
|
||||||
.map((type): ValuePreferences => this.contentTypeMap[type]);
|
|
||||||
const match = getConversionTarget(Object.assign({} as ValuePreferences, ...supported), preferred);
|
|
||||||
if (!match) {
|
if (!match) {
|
||||||
throw new NotImplementedHttpError(`Cannot convert from ${contentType} to ${Object.keys(preferred)}`);
|
throw new NotImplementedHttpError(`Cannot convert from ${contentType} to ${Object.keys(preferred)}`);
|
||||||
}
|
}
|
||||||
|
@ -97,4 +97,14 @@ describe('A ContentTypeReplacer', (): void => {
|
|||||||
expect(result.data).toBe(data);
|
expect(result.data).toBe(data);
|
||||||
expect(result.metadata.contentType).toBe('application/trig');
|
expect(result.metadata.contentType).toBe('application/trig');
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('returns all matching output types.', async(): Promise<void> => {
|
||||||
|
await expect(converter.getOutputTypes('application/n-triples')).resolves.toEqual({
|
||||||
|
'text/turtle': 1,
|
||||||
|
'application/trig': 1,
|
||||||
|
'application/n-quads': 1,
|
||||||
|
'application/octet-stream': 1,
|
||||||
|
'internal/anything': 1,
|
||||||
|
});
|
||||||
|
});
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user