UNPKG

@ui5/server

Version:
274 lines (260 loc) 10.8 kB
import parseurl from "parseurl"; import mime from "mime-types"; import { createReaderCollection, createReaderCollectionPrioritized, createResource, createFilterReader, createLinkReader, createFlatReader } from "@ui5/fs/resourceFactory"; /** * Convenience functions for UI5 Server middleware. * An instance of this class is passed to every standard UI5 Server middleware. * Custom middleware that define a specification version >= 2.0 will also receive an instance * of this class as part of the parameters of their create-middleware function. * * The set of functions that can be accessed by a custom middleware depends on the specification * version defined for the extension. * * @public * @class * @alias @ui5/server/middleware/MiddlewareUtil * @hideconstructor */ class MiddlewareUtil { /** * * @param {object} parameters * @param {@ui5/project/graph/ProjectGraph} parameters.graph Relevant ProjectGraph * @param {@ui5/project/specifications/Project} parameters.project Project that is being served * @public */ constructor({graph, project}) { if (!graph) { throw new Error(`Missing parameter "graph"`); } if (!project) { throw new Error(`Missing parameter "project"`); } this._graph = graph; this._project = project; } /** * Returns the [pathname]{@link https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname} * of a given request. Any escape sequences will be decoded. * </br></br> * This method is only available to custom middleware extensions defining * <b>Specification Version 2.0 and above</b>. * * @param {object} req Request object * @returns {string} [Pathname]{@link https://developer.mozilla.org/en-US/docs/Web/API/URL/pathname} * of the given request * @public */ getPathname(req) { let {pathname} = parseurl(req); pathname = decodeURIComponent(pathname); return pathname; } /** * MIME Info * * @example * const mimeInfo = { * "type": "text/html", * "charset": "utf-8", * "contentType": "text/html; charset=utf-8" * }; * * @public * @typedef {object} MimeInfo * @property {string} type Detected content-type for the given resource path * @property {string} charset Default charset for the detected content-type * @property {string} contentType Calculated content-type header value * @memberof @ui5/server/middleware/MiddlewareUtil */ /** * Returns MIME information derived from a given resource path. * </br></br> * This method is only available to custom middleware extensions defining * <b>Specification Version 2.0 and above</b>. * * @param {object} resourcePath * @returns {@ui5/server/middleware/MiddlewareUtil.MimeInfo} * @public */ getMimeInfo(resourcePath) { const type = mime.lookup(resourcePath) || "application/octet-stream"; const charset = mime.charset(type); return { type, charset, contentType: type + (charset ? "; charset=" + charset : "") }; } /** * Specification Version-dependent [Project]{@link @ui5/project/specifications/Project} interface. * For details on individual functions, see [Project]{@link @ui5/project/specifications/Project} * * @public * @typedef {object} @ui5/server/middleware/MiddlewareUtil~ProjectInterface * @property {Function} getType Get the project type * @property {Function} getName Get the project name * @property {Function} getVersion Get the project version * @property {Function} getNamespace Get the project namespace * @property {Function} getRootReader Get the project rootReader * @property {Function} getReader Get the project reader, defaulting to "runtime" style instead of "buildtime" * @property {Function} getRootPath Get the local File System path of the project's root directory * @property {Function} getSourcePath Get the local File System path of the project's source directory * @property {Function} getCustomConfiguration Get the project Custom Configuration * @property {Function} isFrameworkProject Check whether the project is a UI5-Framework project * @property {Function} getFrameworkName Get the project's framework name configuration * @property {Function} getFrameworkVersion Get the project's framework version configuration * @property {Function} getFrameworkDependencies Get the project's framework dependencies configuration */ /** * Retrieve a single project from the dependency graph * * </br></br> * This method is only available to custom server middleware extensions defining * <b>Specification Version 3.0 and above</b>. * * @param {string|@ui5/fs/Resource} [projectNameOrResource] * Name of the project to retrieve or a Resource instance to retrieve the associated project for. * Defaults to the name of the current root project * @returns {@ui5/server/middleware/MiddlewareUtil~ProjectInterface|undefined} * Specification Version-dependent interface to the Project instance or <code>undefined</code> * if the project name is unknown or the provided resource is not associated with any project. * @public */ getProject(projectNameOrResource) { if (projectNameOrResource) { if (typeof projectNameOrResource === "string" || projectNameOrResource instanceof String) { // A project name has been provided return this._graph.getProject(projectNameOrResource); } else { // A Resource instance has been provided return projectNameOrResource.getProject(); } } // No parameter has been provided, default to the root project return this._project; } /** * Retrieve a list of direct dependencies of a given project from the dependency graph. * Note that this list does not include transitive dependencies. * * </br></br> * This method is only available to custom server middleware extensions defining * <b>Specification Version 3.0 and above</b>. * * @param {string} [projectName] Name of the project to retrieve. * Defaults to the name of the current root project * @returns {string[]} Names of all direct dependencies * @throws {Error} If the requested project is unknown to the graph * @public */ getDependencies(projectName) { return this._graph.getDependencies(projectName || this._project.getName()); } /** * Specification Version-dependent set of [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory} * functions provided to middleware. * For details on individual functions, see [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory} * * @public * @typedef {object} @ui5/server/middleware/MiddlewareUtil~resourceFactory * @property {Function} createResource Creates a [Resource]{@link @ui5/fs/Resource}. * Accepts the same parameters as the [Resource]{@link @ui5/fs/Resource} constructor. * @property {Function} createReaderCollection Creates a reader collection: * [ReaderCollection]{@link @ui5/fs/ReaderCollection} * @property {Function} createReaderCollectionPrioritized Creates a prioritized reader collection: * [ReaderCollectionPrioritized]{@link @ui5/fs/ReaderCollectionPrioritized} * @property {Function} createFilterReader * Create a [Filter-Reader]{@link @ui5/fs/readers/Filter} with the given reader. * @property {Function} createLinkReader * Create a [Link-Reader]{@link @ui5/fs/readers/Filter} with the given reader. * @property {Function} createFlatReader Create a [Link-Reader]{@link @ui5/fs/readers/Link} * where all requests are prefixed with <code>/resources/<namespace></code>. */ /** * Provides limited access to [@ui5/fs/resourceFactory]{@link @ui5/fs/resourceFactory} functions * * </br></br> * This attribute is only available to custom server middleware extensions defining * <b>Specification Version 3.0 and above</b>. * * @type {@ui5/server/middleware/MiddlewareUtil~resourceFactory} * @public */ resourceFactory = { createResource, createReaderCollection, createReaderCollectionPrioritized, createFilterReader, createLinkReader, createFlatReader, }; /** * Get an interface to an instance of this class that only provides those functions * that are supported by the given custom middleware extension specification version. * * @param {@ui5/project/specifications/SpecificationVersion} specVersion * SpecVersionComparator instance of the custom server middleware * @returns {object} An object with bound instance methods supported by the given specification version */ getInterface(specVersion) { if (specVersion.lt("2.0")) { // Custom middleware defining specVersion <2.0 does not have access to any MiddlewareUtil API return undefined; } const baseInterface = {}; bindFunctions(this, baseInterface, [ "getPathname", "getMimeInfo" ]); if (specVersion.gte("3.0")) { // getProject function, returning an interfaced project instance baseInterface.getProject = (projectName) => { const project = this.getProject(projectName); const baseProjectInterface = {}; bindFunctions(project, baseProjectInterface, [ "getType", "getName", "getVersion", "getNamespace", "getRootReader", "getRootPath", "getSourcePath", "getCustomConfiguration", "isFrameworkProject", "getFrameworkName", "getFrameworkVersion", "getFrameworkDependencies" ]); // Project#getReader defaults to style "buildtime". However ui5-server uses // style "runtime". The main difference is that for some project types (like applications) // the /resources/<namespace> path prefix is omitted for "runtime". Also, no builder resource- // exclude configuration is applied. // Therefore default to style "runtime" here so that custom middleware will commonly work with // the same paths as ui5-server and no unexpected builder-excludes. baseProjectInterface.getReader = function(options = {style: "runtime"}) { return project.getReader(options); }; return baseProjectInterface; }; // getDependencies function, returning an array of project names baseInterface.getDependencies = (projectName) => { return this.getDependencies(projectName); }; baseInterface.resourceFactory = Object.create(null); [ // Once new functions get added, extract this array into a variable // and enhance based on spec version once new functions get added "createResource", "createReaderCollection", "createReaderCollectionPrioritized", "createFilterReader", "createLinkReader", "createFlatReader", ].forEach((factoryFunction) => { baseInterface.resourceFactory[factoryFunction] = this.resourceFactory[factoryFunction]; }); } return baseInterface; } } function bindFunctions(sourceObject, targetObject, funcNames) { funcNames.forEach((funcName) => { targetObject[funcName] = sourceObject[funcName].bind(sourceObject); }); } export default MiddlewareUtil;