Repository: nodejs/node
File: lib/internal/crypto/hash.js (JavaScript)

Code before:
  isArrayBufferView,
} = require('internal/util/types');

const LazyTransform = require('internal/streams/lazy_transform');

const kState = Symbol('kState');
const kFinalized = Symbol('kFinalized');

/**
 * @param {string} name
 */
function normalizeAlgorithm(name) {
  return StringPrototypeReplace(StringPrototypeToLowerCase(name), '-', '');
}

let warned = false;
const emitDeprecationWarning = getDeprecationWarningEmitter(
  'DEP0198',
  'Creating SHAKE128/256 digests without an explicit options.outputLength is deprecated.',
  undefined,
  false,
  isPendingDeprecation,
);

function Hash(algorithm, options) {
  if (!new.target)
    return new Hash(algorithm, options);
  const isCopy = algorithm instanceof _Hash;
  if (!isCopy)
    validateString(algorithm, 'algorithm');
  const xofLen = typeof options === 'object' && options !== null ?
    options.outputLength : undefined;
  if (xofLen !== undefined)
    validateUint32(xofLen, 'options.outputLength');
  // Lookup the cached ID from JS land because it's faster than decoding
  // the string in C++ land.
  const algorithmId = isCopy ? -1 : getCachedHashId(algorithm);
  this[kHandle] = new _Hash(algorithm, xofLen, algorithmId, getHashCache());
  this[kState] = {
    [kFinalized]: false,
  };
  if (!warned && !isCopy && xofLen === undefined) {
    const normalized = normalizeAlgorithm(algorithm);
    if (normalized === 'shake128' || normalized === 'shake256') {
      emitDeprecationWarning();
      warned = true;
    }
  }
  ReflectApply(LazyTransform, this, [options]);
}


Review comment (refactor):
nit: Can we move this to the `shouldEmitWarning` callback? If you apply the following diff, that would allow us to have a  cleaner implementation IMO
```diff
diff --git a/lib/internal/util.js b/lib/internal/util.js
index 180ca49b32..41ecff5fdb 100644
--- a/lib/internal/util.js
+++ b/lib/internal/util.js
@@ -111,7 +111,7 @@ function getDeprecationWarningEmitter(
 ) {
   let warned = false;
   return function() {
-    if (!warned && shouldEmitWarning()) {
+    if (!warned && ReflectApply(shouldEmitWarning, this, arguments)) {
       warned = true;
       if (code === 'ExperimentalWarning') {
         process.emitWarning(msg, code, deprecated);
```
```suggestion
const emitDeprecationWarning = getDeprecationWarningEmitter(
  'DEP0198',
  'Creating SHAKE128/256 digests without an explicit options.outputLength is deprecated.',
  undefined,
  false,
  (algorithm) => {
    if (!isPendingDeprecation()) return false;
    const normalized = normalizeAlgorithm(algorithm);
    return normalized === 'shake128' || normalized === 'shake256';
  },
);
```

Code after:
  isArrayBufferView,
} = require('internal/util/types');

const LazyTransform = require('internal/streams/lazy_transform');

const kState = Symbol('kState');
const kFinalized = Symbol('kFinalized');

/**
 * @param {string} name
 */
function normalizeAlgorithm(name) {
  return StringPrototypeReplace(StringPrototypeToLowerCase(name), '-', '');
}

const maybeEmitDeprecationWarning = getDeprecationWarningEmitter(
  'DEP0198',
  'Creating SHAKE128/256 digests without an explicit options.outputLength is deprecated.',
  undefined,
  false,
  (algorithm) => {
    if (!isPendingDeprecation()) return false;
    const normalized = normalizeAlgorithm(algorithm);
    return normalized === 'shake128' || normalized === 'shake256';
  },
);

function Hash(algorithm, options) {
  if (!new.target)
    return new Hash(algorithm, options);
  const isCopy = algorithm instanceof _Hash;
  if (!isCopy)
    validateString(algorithm, 'algorithm');
  const xofLen = typeof options === 'object' && options !== null ?
    options.outputLength : undefined;
  if (xofLen !== undefined)
    validateUint32(xofLen, 'options.outputLength');
  // Lookup the cached ID from JS land because it's faster than decoding
  // the string in C++ land.
  const algorithmId = isCopy ? -1 : getCachedHashId(algorithm);
  this[kHandle] = new _Hash(algorithm, xofLen, algorithmId, getHashCache());
  this[kState] = {
    [kFinalized]: false,
  };
  if (!isCopy && xofLen === undefined) {
    maybeEmitDeprecationWarning(algorithm);
  }
  ReflectApply(LazyTransform, this, [options]);
}

ObjectSetPrototypeOf(Hash.prototype, LazyTransform.prototype);