<commit_before>const authTools = require("./auth.js");
const urlTools = require("./url.js");
const { merge } = require("./merge.js");

const directoryContents = require("./interface/directoryContents.js");
const createDir = require("./interface/createDirectory.js");
const custom = require("./interface/custom.js");
const deletion = require("./interface/delete.js");
const pathsExist = require("./interface/exists.js");
const getFile = require("./interface/getFile.js");
const quota = require("./interface/quota.js");
const move = require("./interface/moveFile.js");
const copy = require("./interface/copyFile.js");
const putFile = require("./interface/putFile.js");
const stats = require("./interface/stat.js");

/**
 * Client adapter
 * @typedef {Object} ClientInterface
 */

/**
 * Options for creating a resource
 * @typedef {UserOptions} PutOptions
 * @property {Boolean=} overwrite - Whether or not to overwrite existing files (default: true)
 */

/**
 * Options with headers and format
 * @typedef {UserOptions} OptionsWithFormat
 * @property {String} format - The format to use (text/binary)
 * @property {Boolean=} details - Provided detailed response information, such as response
 *  headers (defaults to false). Only available on requests that return result data.
 */

/**
 * Options for methods that resturn responses
 * @typedef {UserOptions} OptionsForAdvancedResponses
 * @property {Boolean=} details - Provided detailed response information, such as response
 *  headers (defaults to false). Only available on requests that return result data.
 */

/**
 * @typedef {OptionsForAdvancedResponses} GetDirectoryContentsOptions
 * @property {Boolean=} deep - Return deep (infinite) items (default: false)
 * @property {String=} glob - Glob pattern for matching certain files
 */

/**
 * @typedef {Object} AuthToken
 * @property {String} token_type - The type of token (eg "Bearer")
 * @property {String} access_token - The token access code
 */

/**
 * @typedef {Object} CreateClientOptions
 * @property {String=} username - The username for authentication
 * @property {String=} password - The password for authentication
 * @property {http.Agent=} httpAgent - Override the HTTP Agent instance for requests
 * @property {https.Agent=} httpsAgent - Override the HTTPS Agent instance for requests
 * @property {AuthToken=} token - Optional OAuth token
 */

/**
 * A stat result
 * @typedef {Object} Stat
 * @property {String} filename The full path and filename of the remote item
 * @property {String} basename The base filename of the remote item, without the path
 * @property {String|null} lastmod The last modification date (eg. "Sun, 13 Mar 2016 04:23:32 GMT")
 * @property {Number} size The size of the remote item
 * @property {String} type The type of the item (file/directory)
 * @property {String=} mime The file mimetype (not present on directories)
 * @property {String|null} etag The ETag of the remote item (as supported by the server)
 * @property {Object=} props Additionally returned properties from the server, unprocessed, if
 *     `details: true` is specified in the options
 */

/**
 * Create a client adapter
 * @param {String} remoteURL The remote address of the webdav server
 * @param {CreateClientOptions=} opts Client options
 * @returns {ClientInterface} A new client interface instance
 * @memberof module:WebDAV
 * @example
 *  const createClient = require("webdav");
 *  const client = createClient(url, { username, password });
 *  client
 *      .getDirectoryContents("/")
 *      .then(contents => {
 *          console.log(contents);
 *      });
 * @example
 *  const createClient = require("webdav");
 *  const client = createClient(url, {
 *      token: { token_type: "Bearer", access_token: "tokenvalue" }
 *  });
 *  client
 *      .getDirectoryContents("/")
 *      .then(contents => {
 *          console.log(contents);
 *      });
 */
function createClient(remoteURL, opts = {}) {
    if (!opts || typeof opts !== "object") {
        throw new Error("Options must be an object, if specified");
    }
    const { username, password, httpAgent, httpsAgent, token = null, digest = false } = opts;
    const runtimeOptions = {
        headers: {},
        remotePath: urlTools.extractURLPath(remoteURL),
        remoteURL,
        httpAgent,
        httpsAgent
    };
    // Configure auth
    if (digest) {
        runtimeOptions._digest = { username, password, nc: 0, algorithm: "md5", hasDigestAuth: false };
    } else if (username) {
        runtimeOptions.headers.Authorization = authTools.generateBasicAuthHeader(username, password);
    } else if (token && typeof token === "object") {
        runtimeOptions.headers.Authorization = authTools.generateTokenAuthHeader(token);
    }
    return {
        /**
         * Copy a remote item to another path
         * @param {String} remotePath The remote item path
         * @param {String} targetRemotePath The path file will be copied to
         * @param {UserOptions=} options Options for the request
         * @memberof ClientInterface
         * @returns {Promise} A promise that resolves once the request has completed
         * @example
         *      await client.copyFile("/photos/pic1.jpg", "/backup/pic1.jpg");
         */
        copyFile: function copyFile(remotePath, targetRemotePath, options) {
            const copyOptions = merge(runtimeOptions, options || {});
            return copy.copyFile(remotePath, targetRemotePath, copyOptions);
        },

        /**
         * Create a directory
         * @param {String} dirPath The path to create
         * @param {UserOptions=} options Options for the request
         * @memberof ClientInterface
         * @returns {Promise} A promise that resolves when the remote path has been created
         * @example
         *      await client.createDirectory("/my/directory");
         */
        createDirectory: function createDirectory(dirPath, options) {
            const createOptions = merge(runtimeOptions, options || {});
            return createDir.createDirectory(dirPath, createOptions);
        },

        /**
         * Create a readable stream of a remote file
         * @param {String} remoteFilename The file to stream
         * @param {UserOptions=} options Options for the request
         * @memberof ClientInterface
         * @returns {Readable} A readable stream
         * @example
         *      const remote = client.createReadStream("/data.zip");
         *      remote.pipe(someWriteStream);
         */
        createReadStream: function createReadStream(remoteFilename, options) {
            if (typeof WEB !== "undefined" && WEB === true) {
                throw new Error("createReadStream not implemented in web environment");
            } else {
                const createStream = require("./interface/createStream.js");
                const createOptions = merge(runtimeOptions, options || {});
                return createStream.createReadStream(remoteFilename, createOptions);
            }
        },

        /**
         * Create a writeable stream to a remote file
         * @param {String} remoteFilename The file to write to
         * @param {PutOptions=} options Options for the request
         * @param {Function} callback Callback when response is received
         * @memberof ClientInterface
         * @returns {Writeable} A writeable stream
         * @example
         *      const remote = client.createWriteStream("/data.zip");
         *      fs.createReadStream("~/myData.zip").pipe(remote);
         */
        createWriteStream: function createWriteStream(remoteFilename, options, callback) {
            if (typeof WEB !== "undefined" && WEB === true) {
                throw new Error("createWriteStream not implemented in web environment");
            } else {
                const createStream = require("./interface/createStream.js");
                const createOptions = merge(runtimeOptions, options || {});
                return createStream.createWriteStream(remoteFilename, createOptions, callback);
            }
        },

        /**
         * Send a custom request
         * @param {String} remotePath The remote path
         * @param {RequestOptions=}  requestOptions the request options
         * @param {Options=} options Options for the request
         * @memberof ClientInterface
         * @returns {Promise<Any>} A promise that resolves with response of the request
         * @example
         *      const contents = await client.customRequest("/alrighty.jpg", {
         *          method: "PROPFIND",
         *          headers: {
         *              Accept: "text/plain",
         *              Depth: 0
         *          },
         *          responseType: "text"
         *      });
         */<commit_msg>Add NOOP to createWriteStream method<commit_after>const authTools = require("./auth.js");
const urlTools = require("./url.js");
const { merge } = require("./merge.js");

const directoryContents = require("./interface/directoryContents.js");
const createDir = require("./interface/createDirectory.js");
const custom = require("./interface/custom.js");
const deletion = require("./interface/delete.js");
const pathsExist = require("./interface/exists.js");
const getFile = require("./interface/getFile.js");
const quota = require("./interface/quota.js");
const move = require("./interface/moveFile.js");
const copy = require("./interface/copyFile.js");
const putFile = require("./interface/putFile.js");
const stats = require("./interface/stat.js");

const NOOP = () => {};

/**
 * Client adapter
 * @typedef {Object} ClientInterface
 */

/**
 * Options for creating a resource
 * @typedef {UserOptions} PutOptions
 * @property {Boolean=} overwrite - Whether or not to overwrite existing files (default: true)
 */

/**
 * Options with headers and format
 * @typedef {UserOptions} OptionsWithFormat
 * @property {String} format - The format to use (text/binary)
 * @property {Boolean=} details - Provided detailed response information, such as response
 *  headers (defaults to false). Only available on requests that return result data.
 */

/**
 * Options for methods that resturn responses
 * @typedef {UserOptions} OptionsForAdvancedResponses
 * @property {Boolean=} details - Provided detailed response information, such as response
 *  headers (defaults to false). Only available on requests that return result data.
 */

/**
 * @typedef {OptionsForAdvancedResponses} GetDirectoryContentsOptions
 * @property {Boolean=} deep - Return deep (infinite) items (default: false)
 * @property {String=} glob - Glob pattern for matching certain files
 */

/**
 * @typedef {Object} AuthToken
 * @property {String} token_type - The type of token (eg "Bearer")
 * @property {String} access_token - The token access code
 */

/**
 * @typedef {Object} CreateClientOptions
 * @property {String=} username - The username for authentication
 * @property {String=} password - The password for authentication
 * @property {http.Agent=} httpAgent - Override the HTTP Agent instance for requests
 * @property {https.Agent=} httpsAgent - Override the HTTPS Agent instance for requests
 * @property {AuthToken=} token - Optional OAuth token
 */

/**
 * A stat result
 * @typedef {Object} Stat
 * @property {String} filename The full path and filename of the remote item
 * @property {String} basename The base filename of the remote item, without the path
 * @property {String|null} lastmod The last modification date (eg. "Sun, 13 Mar 2016 04:23:32 GMT")
 * @property {Number} size The size of the remote item
 * @property {String} type The type of the item (file/directory)
 * @property {String=} mime The file mimetype (not present on directories)
 * @property {String|null} etag The ETag of the remote item (as supported by the server)
 * @property {Object=} props Additionally returned properties from the server, unprocessed, if
 *     `details: true` is specified in the options
 */

/**
 * Create a client adapter
 * @param {String} remoteURL The remote address of the webdav server
 * @param {CreateClientOptions=} opts Client options
 * @returns {ClientInterface} A new client interface instance
 * @memberof module:WebDAV
 * @example
 *  const createClient = require("webdav");
 *  const client = createClient(url, { username, password });
 *  client
 *      .getDirectoryContents("/")
 *      .then(contents => {
 *          console.log(contents);
 *      });
 * @example
 *  const createClient = require("webdav");
 *  const client = createClient(url, {
 *      token: { token_type: "Bearer", access_token: "tokenvalue" }
 *  });
 *  client
 *      .getDirectoryContents("/")
 *      .then(contents => {
 *          console.log(contents);
 *      });
 */
function createClient(remoteURL, opts = {}) {
    if (!opts || typeof opts !== "object") {
        throw new Error("Options must be an object, if specified");
    }
    const { username, password, httpAgent, httpsAgent, token = null, digest = false } = opts;
    const runtimeOptions = {
        headers: {},
        remotePath: urlTools.extractURLPath(remoteURL),
        remoteURL,
        httpAgent,
        httpsAgent
    };
    // Configure auth
    if (digest) {
        runtimeOptions._digest = { username, password, nc: 0, algorithm: "md5", hasDigestAuth: false };
    } else if (username) {
        runtimeOptions.headers.Authorization = authTools.generateBasicAuthHeader(username, password);
    } else if (token && typeof token === "object") {
        runtimeOptions.headers.Authorization = authTools.generateTokenAuthHeader(token);
    }
    return {
        /**
         * Copy a remote item to another path
         * @param {String} remotePath The remote item path
         * @param {String} targetRemotePath The path file will be copied to
         * @param {UserOptions=} options Options for the request
         * @memberof ClientInterface
         * @returns {Promise} A promise that resolves once the request has completed
         * @example
         *      await client.copyFile("/photos/pic1.jpg", "/backup/pic1.jpg");
         */
        copyFile: function copyFile(remotePath, targetRemotePath, options) {
            const copyOptions = merge(runtimeOptions, options || {});
            return copy.copyFile(remotePath, targetRemotePath, copyOptions);
        },

        /**
         * Create a directory
         * @param {String} dirPath The path to create
         * @param {UserOptions=} options Options for the request
         * @memberof ClientInterface
         * @returns {Promise} A promise that resolves when the remote path has been created
         * @example
         *      await client.createDirectory("/my/directory");
         */
        createDirectory: function createDirectory(dirPath, options) {
            const createOptions = merge(runtimeOptions, options || {});
            return createDir.createDirectory(dirPath, createOptions);
        },

        /**
         * Create a readable stream of a remote file
         * @param {String} remoteFilename The file to stream
         * @param {UserOptions=} options Options for the request
         * @memberof ClientInterface
         * @returns {Readable} A readable stream
         * @example
         *      const remote = client.createReadStream("/data.zip");
         *      remote.pipe(someWriteStream);
         */
        createReadStream: function createReadStream(remoteFilename, options) {
            if (typeof WEB !== "undefined" && WEB === true) {
                throw new Error("createReadStream not implemented in web environment");
            } else {
                const createStream = require("./interface/createStream.js");
                const createOptions = merge(runtimeOptions, options || {});
                return createStream.createReadStream(remoteFilename, createOptions);
            }
        },

        /**
         * Create a writeable stream to a remote file
         * @param {String} remoteFilename The file to write to
         * @param {PutOptions=} options Options for the request
         * @param {Function=} callback Optional callback to fire
         *  once the request has finished
         * @memberof ClientInterface
         * @returns {Writeable} A writeable stream
         * @example
         *      const remote = client.createWriteStream("/data.zip");
         *      fs.createReadStream("~/myData.zip").pipe(remote);
         */
        createWriteStream: function createWriteStream(remoteFilename, options, callback = NOOP) {
            if (typeof WEB !== "undefined" && WEB === true) {
                throw new Error("createWriteStream not implemented in web environment");
            } else {
                const createStream = require("./interface/createStream.js");
                const createOptions = merge(runtimeOptions, options || {});
                return createStream.createWriteStream(remoteFilename, createOptions, callback);
            }
        },

        /**
         * Send a custom request
         * @param {String} remotePath The remote path
         * @param {RequestOptions=}  requestOptions the request options
         * @param {Options=} options Options for the request
         * @memberof ClientInterface
         * @returns {Promise<Any>} A promise that resolves with response of the request
         * @example
         *      const contents = await client.customRequest("/alrighty.jpg", {
         *          method: "PROPFIND",
         *          headers: {
         *              Accept: "text/plain",
         *              Depth: 0
         *          },
         *          responseType: "text"
         *      });
         */
{'fraction_non_alphanumeric': 0.1112053369516056, 'fraction_numerical': 0.001922207146087743, 'mean_word_length': 2.761216244950032, 'pattern_counts': {'":': 0, '<': 5, '<?xml version=': 0, '>': 10, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '185491', 'n_tokens_mistral': 4516, 'n_tokens_neox': 4401, 'n_words': 1487}