@tdb/web
Version:
Common condiguration for serving a web-site and testing web-based UI components.
125 lines (107 loc) • 2.97 kB
text/typescript
import { fs, fsPath, value } from '../common';
import {
IManifestResource,
ManifestFileType,
IManifestFolder,
IManifestFile,
IManifestJson,
IManifestYaml,
} from './types';
import {
toManifestImage,
parseJson,
parseYaml,
toManifestMarkdown,
} from './util';
/**
* Creates an IResource.
*/
export async function toResource(args: {
rootPath: string;
filePath: string;
urlPrefix?: string;
loadExtensions?: string[];
}): Promise<IManifestResource | undefined> {
const { rootPath, filePath, urlPrefix, loadExtensions = [] } = args;
const file = fsPath.parse(filePath);
let body: string | undefined;
let error: IManifestResource['error'] | undefined;
const type = await toFileType(filePath);
// Load body of document if requested.
const ext = (file.ext || '').replace(/^\./, '');
if (loadExtensions.includes(ext)) {
try {
body = (await fs.readFile(filePath)).toString();
} catch (err) {
const message = `Failed to load body. ${err.message}`;
error = { message };
}
}
// Resolve path to the file.
let path = filePath.substr(rootPath.length);
path = urlPrefix ? fsPath.join(urlPrefix, path) : path;
// Convert to specific manifest type.
let result: IManifestResource | undefined;
switch (type) {
case 'FOLDER':
const folder: IManifestFolder = { type: 'FOLDER', path };
result = folder;
break;
case 'FILE':
const file: IManifestFile = { type: 'FILE', path };
result = file;
break;
case 'FILE/image':
const image = await toManifestImage(filePath, path, { size: true });
result = image;
break;
case 'FILE/markdown':
const markdown = await toManifestMarkdown(path, body);
result = markdown;
break;
case 'FILE/json':
const manifestJson: IManifestJson = {
type: 'FILE/json',
path,
...parseJson(body),
};
result = manifestJson;
break;
case 'FILE/yaml':
const manifestYaml: IManifestYaml = {
type: 'FILE/yaml',
path,
...parseYaml(body),
};
result = manifestYaml;
break;
default:
throw new Error(`File type '${type}' not supported.`);
}
// Finish up.
error = result && result.error ? result.error : error;
return result ? value.deleteUndefined({ ...result, error }) : undefined;
}
/**
* Determine the file-type of the given file.
*/
export async function toFileType(path: string): Promise<ManifestFileType> {
if ((await fs.lstat(path)).isDirectory()) {
return 'FOLDER';
}
const file = fsPath.parse(path);
const ext = file.ext.toLowerCase();
if (['.md', '.markdown'].includes(ext)) {
return 'FILE/markdown';
}
if (['.jpg', '.jpeg', '.png', '.svg'].includes(ext)) {
return 'FILE/image';
}
if (['.json'].includes(ext)) {
return 'FILE/json';
}
if (['.yml', '.yaml'].includes(ext)) {
return 'FILE/yaml';
}
return 'FILE';
}