@typespec/ts-http-runtime
Version:
Isomorphic client library for making HTTP requests in node.js and browser.
186 lines • 6.29 kB
JavaScript
// Copyright (c) Microsoft Corporation.
// Licensed under the MIT License.
import { log } from "./log-web.mjs";
import { getEnvironmentVariable } from "../env-browser.mjs";
const debugEnvVariable = getEnvironmentVariable("DEBUG");
let enabledString;
let enabledNamespaces = [];
let skippedNamespaces = [];
const debuggers = [];
if (debugEnvVariable) {
enable(debugEnvVariable);
}
const debugObj = Object.assign((namespace) => {
return createDebugger(namespace);
}, {
enable,
enabled,
disable,
log,
});
function enable(namespaces) {
enabledString = namespaces;
enabledNamespaces = [];
skippedNamespaces = [];
const namespaceList = namespaces.split(",").map((ns) => ns.trim());
for (const ns of namespaceList) {
if (ns.startsWith("-")) {
skippedNamespaces.push(ns.substring(1));
}
else {
enabledNamespaces.push(ns);
}
}
for (const instance of debuggers) {
instance.enabled = enabled(instance.namespace);
}
}
function enabled(namespace) {
if (namespace.endsWith("*")) {
return true;
}
for (const skipped of skippedNamespaces) {
if (namespaceMatches(namespace, skipped)) {
return false;
}
}
for (const enabledNamespace of enabledNamespaces) {
if (namespaceMatches(namespace, enabledNamespace)) {
return true;
}
}
return false;
}
/**
* Given a namespace, check if it matches a pattern.
* Patterns only have a single wildcard character which is *.
* The behavior of * is that it matches zero or more other characters.
*/
function namespaceMatches(namespace, patternToMatch) {
// simple case, no pattern matching required
if (patternToMatch.indexOf("*") === -1) {
return namespace === patternToMatch;
}
let pattern = patternToMatch;
// normalize successive * if needed
if (patternToMatch.indexOf("**") !== -1) {
const patternParts = [];
let lastCharacter = "";
for (const character of patternToMatch) {
if (character === "*" && lastCharacter === "*") {
continue;
}
else {
lastCharacter = character;
patternParts.push(character);
}
}
pattern = patternParts.join("");
}
let namespaceIndex = 0;
let patternIndex = 0;
const patternLength = pattern.length;
const namespaceLength = namespace.length;
let lastWildcard = -1;
let lastWildcardNamespace = -1;
while (namespaceIndex < namespaceLength && patternIndex < patternLength) {
if (pattern[patternIndex] === "*") {
lastWildcard = patternIndex;
patternIndex++;
if (patternIndex === patternLength) {
// if wildcard is the last character, it will match the remaining namespace string
return true;
}
// now we let the wildcard eat characters until we match the next literal in the pattern
while (namespace[namespaceIndex] !== pattern[patternIndex]) {
namespaceIndex++;
// reached the end of the namespace without a match
if (namespaceIndex === namespaceLength) {
return false;
}
}
// now that we have a match, let's try to continue on
// however, it's possible we could find a later match
// so keep a reference in case we have to backtrack
lastWildcardNamespace = namespaceIndex;
namespaceIndex++;
patternIndex++;
continue;
}
else if (pattern[patternIndex] === namespace[namespaceIndex]) {
// simple case: literal pattern matches so keep going
patternIndex++;
namespaceIndex++;
}
else if (lastWildcard >= 0) {
// special case: we don't have a literal match, but there is a previous wildcard
// which we can backtrack to and try having the wildcard eat the match instead
patternIndex = lastWildcard + 1;
namespaceIndex = lastWildcardNamespace + 1;
// we've reached the end of the namespace without a match
if (namespaceIndex === namespaceLength) {
return false;
}
// similar to the previous logic, let's keep going until we find the next literal match
while (namespace[namespaceIndex] !== pattern[patternIndex]) {
namespaceIndex++;
if (namespaceIndex === namespaceLength) {
return false;
}
}
lastWildcardNamespace = namespaceIndex;
namespaceIndex++;
patternIndex++;
continue;
}
else {
return false;
}
}
const namespaceDone = namespaceIndex === namespace.length;
const patternDone = patternIndex === pattern.length;
// this is to detect the case of an unneeded final wildcard
// e.g. the pattern `ab*` should match the string `ab`
const trailingWildCard = patternIndex === pattern.length - 1 && pattern[patternIndex] === "*";
return namespaceDone && (patternDone || trailingWildCard);
}
function disable() {
const result = enabledString || "";
enable("");
return result;
}
function createDebugger(namespace) {
const newDebugger = Object.assign(debug, {
enabled: enabled(namespace),
destroy,
log: debugObj.log,
namespace,
extend,
});
function debug(...args) {
if (!newDebugger.enabled) {
return;
}
if (args.length > 0) {
args[0] = `${namespace} ${args[0]}`;
}
newDebugger.log(...args);
}
debuggers.push(newDebugger);
return newDebugger;
}
function destroy() {
const index = debuggers.indexOf(this);
if (index >= 0) {
debuggers.splice(index, 1);
return true;
}
return false;
}
function extend(namespace) {
const newDebugger = createDebugger(`${this.namespace}:${namespace}`);
newDebugger.log = this.log;
return newDebugger;
}
export default debugObj;
//# sourceMappingURL=debug.js.map