Add stylelint dependency

This also adds CC-BY-4.0 to the list of accepted licenses.

DISABLE_THIRD_PARTY_CHECK=update dependencies

Bug: chromium:1083142
Change-Id: I8612de2fba52dae32eeb71af79d5aacfde52142b
Reviewed-on: https://chromium-review.googlesource.com/c/devtools/devtools-frontend/+/2220097
Reviewed-by: Paul Lewis <aerotwist@chromium.org>
Commit-Queue: Mathias Bynens <mathias@chromium.org>
diff --git a/node_modules/write-file-atomic/index.js b/node_modules/write-file-atomic/index.js
new file mode 100644
index 0000000..df5b72a
--- /dev/null
+++ b/node_modules/write-file-atomic/index.js
@@ -0,0 +1,259 @@
+'use strict'
+module.exports = writeFile
+module.exports.sync = writeFileSync
+module.exports._getTmpname = getTmpname // for testing
+module.exports._cleanupOnExit = cleanupOnExit
+
+const fs = require('fs')
+const MurmurHash3 = require('imurmurhash')
+const onExit = require('signal-exit')
+const path = require('path')
+const isTypedArray = require('is-typedarray')
+const typedArrayToBuffer = require('typedarray-to-buffer')
+const { promisify } = require('util')
+const activeFiles = {}
+
+// if we run inside of a worker_thread, `process.pid` is not unique
+/* istanbul ignore next */
+const threadId = (function getId () {
+  try {
+    const workerThreads = require('worker_threads')
+
+    /// if we are in main thread, this is set to `0`
+    return workerThreads.threadId
+  } catch (e) {
+    // worker_threads are not available, fallback to 0
+    return 0
+  }
+})()
+
+let invocations = 0
+function getTmpname (filename) {
+  return filename + '.' +
+    MurmurHash3(__filename)
+      .hash(String(process.pid))
+      .hash(String(threadId))
+      .hash(String(++invocations))
+      .result()
+}
+
+function cleanupOnExit (tmpfile) {
+  return () => {
+    try {
+      fs.unlinkSync(typeof tmpfile === 'function' ? tmpfile() : tmpfile)
+    } catch (_) {}
+  }
+}
+
+function serializeActiveFile (absoluteName) {
+  return new Promise(resolve => {
+    // make a queue if it doesn't already exist
+    if (!activeFiles[absoluteName]) activeFiles[absoluteName] = []
+
+    activeFiles[absoluteName].push(resolve) // add this job to the queue
+    if (activeFiles[absoluteName].length === 1) resolve() // kick off the first one
+  })
+}
+
+// https://github.com/isaacs/node-graceful-fs/blob/master/polyfills.js#L315-L342
+function isChownErrOk (err) {
+  if (err.code === 'ENOSYS') {
+    return true
+  }
+
+  const nonroot = !process.getuid || process.getuid() !== 0
+  if (nonroot) {
+    if (err.code === 'EINVAL' || err.code === 'EPERM') {
+      return true
+    }
+  }
+
+  return false
+}
+
+async function writeFileAsync (filename, data, options = {}) {
+  if (typeof options === 'string') {
+    options = { encoding: options }
+  }
+
+  let fd
+  let tmpfile
+  /* istanbul ignore next -- The closure only gets called when onExit triggers */
+  const removeOnExitHandler = onExit(cleanupOnExit(() => tmpfile))
+  const absoluteName = path.resolve(filename)
+
+  try {
+    await serializeActiveFile(absoluteName)
+    const truename = await promisify(fs.realpath)(filename).catch(() => filename)
+    tmpfile = getTmpname(truename)
+
+    if (!options.mode || !options.chown) {
+      // Either mode or chown is not explicitly set
+      // Default behavior is to copy it from original file
+      const stats = await promisify(fs.stat)(truename).catch(() => {})
+      if (stats) {
+        if (options.mode == null) {
+          options.mode = stats.mode
+        }
+
+        if (options.chown == null && process.getuid) {
+          options.chown = { uid: stats.uid, gid: stats.gid }
+        }
+      }
+    }
+
+    fd = await promisify(fs.open)(tmpfile, 'w', options.mode)
+    if (options.tmpfileCreated) {
+      await options.tmpfileCreated(tmpfile)
+    }
+    if (isTypedArray(data)) {
+      data = typedArrayToBuffer(data)
+    }
+    if (Buffer.isBuffer(data)) {
+      await promisify(fs.write)(fd, data, 0, data.length, 0)
+    } else if (data != null) {
+      await promisify(fs.write)(fd, String(data), 0, String(options.encoding || 'utf8'))
+    }
+
+    if (options.fsync !== false) {
+      await promisify(fs.fsync)(fd)
+    }
+
+    await promisify(fs.close)(fd)
+    fd = null
+
+    if (options.chown) {
+      await promisify(fs.chown)(tmpfile, options.chown.uid, options.chown.gid).catch(err => {
+        if (!isChownErrOk(err)) {
+          throw err
+        }
+      })
+    }
+
+    if (options.mode) {
+      await promisify(fs.chmod)(tmpfile, options.mode).catch(err => {
+        if (!isChownErrOk(err)) {
+          throw err
+        }
+      })
+    }
+
+    await promisify(fs.rename)(tmpfile, truename)
+  } finally {
+    if (fd) {
+      await promisify(fs.close)(fd).catch(
+        /* istanbul ignore next */
+        () => {}
+      )
+    }
+    removeOnExitHandler()
+    await promisify(fs.unlink)(tmpfile).catch(() => {})
+    activeFiles[absoluteName].shift() // remove the element added by serializeSameFile
+    if (activeFiles[absoluteName].length > 0) {
+      activeFiles[absoluteName][0]() // start next job if one is pending
+    } else delete activeFiles[absoluteName]
+  }
+}
+
+function writeFile (filename, data, options, callback) {
+  if (options instanceof Function) {
+    callback = options
+    options = {}
+  }
+
+  const promise = writeFileAsync(filename, data, options)
+  if (callback) {
+    promise.then(callback, callback)
+  }
+
+  return promise
+}
+
+function writeFileSync (filename, data, options) {
+  if (typeof options === 'string') options = { encoding: options }
+  else if (!options) options = {}
+  try {
+    filename = fs.realpathSync(filename)
+  } catch (ex) {
+    // it's ok, it'll happen on a not yet existing file
+  }
+  const tmpfile = getTmpname(filename)
+
+  if (!options.mode || !options.chown) {
+    // Either mode or chown is not explicitly set
+    // Default behavior is to copy it from original file
+    try {
+      const stats = fs.statSync(filename)
+      options = Object.assign({}, options)
+      if (!options.mode) {
+        options.mode = stats.mode
+      }
+      if (!options.chown && process.getuid) {
+        options.chown = { uid: stats.uid, gid: stats.gid }
+      }
+    } catch (ex) {
+      // ignore stat errors
+    }
+  }
+
+  let fd
+  const cleanup = cleanupOnExit(tmpfile)
+  const removeOnExitHandler = onExit(cleanup)
+
+  let threw = true
+  try {
+    fd = fs.openSync(tmpfile, 'w', options.mode || 0o666)
+    if (options.tmpfileCreated) {
+      options.tmpfileCreated(tmpfile)
+    }
+    if (isTypedArray(data)) {
+      data = typedArrayToBuffer(data)
+    }
+    if (Buffer.isBuffer(data)) {
+      fs.writeSync(fd, data, 0, data.length, 0)
+    } else if (data != null) {
+      fs.writeSync(fd, String(data), 0, String(options.encoding || 'utf8'))
+    }
+    if (options.fsync !== false) {
+      fs.fsyncSync(fd)
+    }
+
+    fs.closeSync(fd)
+    fd = null
+
+    if (options.chown) {
+      try {
+        fs.chownSync(tmpfile, options.chown.uid, options.chown.gid)
+      } catch (err) {
+        if (!isChownErrOk(err)) {
+          throw err
+        }
+      }
+    }
+
+    if (options.mode) {
+      try {
+        fs.chmodSync(tmpfile, options.mode)
+      } catch (err) {
+        if (!isChownErrOk(err)) {
+          throw err
+        }
+      }
+    }
+
+    fs.renameSync(tmpfile, filename)
+    threw = false
+  } finally {
+    if (fd) {
+      try {
+        fs.closeSync(fd)
+      } catch (ex) {
+        // ignore close errors at this stage, error may have closed fd already.
+      }
+    }
+    removeOnExitHandler()
+    if (threw) {
+      cleanup()
+    }
+  }
+}