Convert docs to docsy

This commit is contained in:
Phillip Wittrock
2020-06-07 21:07:46 -07:00
parent 25a38ad2b6
commit 42497c664f
11469 changed files with 816051 additions and 4557 deletions

View File

@@ -0,0 +1,20 @@
{
"env": {
"browser": false,
"node": true
},
"parserOptions": {
"sourceType": "script"
},
"extends": "../.eslintrc.json",
"rules": {
"consistent-return": "off",
"func-style": "off",
"no-console": "off",
"no-magic-numbers": "off",
"no-process-env": "off",
"no-process-exit": "off",
"no-sync": "off",
"spaced-comment": "off"
}
}

View File

@@ -0,0 +1,44 @@
{
"attr-bans": ["align", "background", "bgcolor", "border", "frameborder", "longdesc", "marginwidth", "marginheight", "scrolling"],
"attr-name-style": false,
"attr-no-dup": true,
"attr-no-unsafe-char": true,
"attr-quote-style": "double",
"attr-req-value": true,
"attr-validate": false,
"class-no-dup": true,
"class-style": "none",
"doctype-first": true,
"doctype-html5": true,
"fig-req-figcaption": false,
"focusable-tabindex-style": true,
"head-req-title": true,
"head-valid-content-model": false,
"href-style": false,
"html-req-lang": true,
"html-valid-content-model": false,
"id-class-ignore-regex": "(onclick|content|[a-z]+([A-Z][a-z])+)",
"id-class-no-ad": true,
"id-class-style": false,
"id-no-dup": true,
"img-req-alt": "allownull",
"img-req-src": false,
"indent-style": "spaces",
"indent-width": 2,
"input-radio-req-name": false,
"input-req-label": false,
"label-req-for": true,
"lang-style": "case",
"line-no-trailing-whitespace": false,
"line-end-style": "lf",
"spec-char-escape": false,
"table-req-header": false,
"tag-bans": ["b", "i"],
"tag-close": true,
"tag-name-lowercase": true,
"tag-name-match": true,
"tag-self-close": false,
"text-ignore-regex": false,
"title-max-len": 70,
"title-no-dup": true
}

View File

@@ -0,0 +1,81 @@
/*!
* Script to build our plugins to use them separately.
* Copyright 2018 The Bootstrap Authors
* Copyright 2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
'use strict'
const rollup = require('rollup')
const path = require('path')
const babel = require('rollup-plugin-babel')
const TEST = process.env.NODE_ENV === 'test'
const plugins = [
babel({
exclude: 'node_modules/**', // Only transpile our source code
externalHelpersWhitelist: [ // Include only required helpers
'defineProperties',
'createClass',
'inheritsLoose',
'defineProperty',
'objectSpread'
]
})
]
const format = 'umd'
const rootPath = !TEST ? '../js/dist/' : '../js/coverage/dist/'
const bsPlugins = {
Alert: path.resolve(__dirname, '../js/src/alert.js'),
Button: path.resolve(__dirname, '../js/src/button.js'),
Carousel: path.resolve(__dirname, '../js/src/carousel.js'),
Collapse: path.resolve(__dirname, '../js/src/collapse.js'),
Dropdown: path.resolve(__dirname, '../js/src/dropdown.js'),
Modal: path.resolve(__dirname, '../js/src/modal.js'),
Popover: path.resolve(__dirname, '../js/src/popover.js'),
ScrollSpy: path.resolve(__dirname, '../js/src/scrollspy.js'),
Tab: path.resolve(__dirname, '../js/src/tab.js'),
Tooltip: path.resolve(__dirname, '../js/src/tooltip.js'),
Util: path.resolve(__dirname, '../js/src/util.js')
}
Object.keys(bsPlugins)
.forEach((pluginKey) => {
console.log(`Building ${pluginKey} plugin...`)
const external = ['jquery', 'popper.js']
const globals = {
jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode
'popper.js': 'Popper'
}
// Do not bundle Util in plugins
if (pluginKey !== 'Util') {
external.push(bsPlugins.Util)
globals[bsPlugins.Util] = 'Util'
}
// Do not bundle Tooltip in Popover
if (pluginKey === 'Popover') {
external.push(bsPlugins.Tooltip)
globals[bsPlugins.Tooltip] = 'Tooltip'
}
rollup.rollup({
input: bsPlugins[pluginKey],
plugins,
external
}).then((bundle) => {
bundle.write({
format,
name: pluginKey,
sourcemap: true,
globals,
file: path.resolve(__dirname, `${rootPath}${pluginKey.toLowerCase()}.js`)
})
.then(() => console.log(`Building ${pluginKey} plugin... Done !`))
.catch((err) => console.error(`${pluginKey}: ${err}`))
})
})

View File

@@ -0,0 +1,104 @@
#!/usr/bin/env node
/*!
* Script to update version number references in the project.
* Copyright 2017-2018 The Bootstrap Authors
* Copyright 2017-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
'use strict'
const fs = require('fs')
const path = require('path')
const sh = require('shelljs')
sh.config.fatal = true
// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
function regExpQuote(string) {
return string.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
}
function regExpQuoteReplacement(string) {
return string.replace(/[$]/g, '$$')
}
const DRY_RUN = false
function walkAsync(directory, excludedDirectories, fileCallback, errback) {
if (excludedDirectories.has(path.parse(directory).base)) {
return
}
fs.readdir(directory, (err, names) => {
if (err) {
errback(err)
return
}
names.forEach((name) => {
const filepath = path.join(directory, name)
fs.lstat(filepath, (err, stats) => {
if (err) {
process.nextTick(errback, err)
return
}
if (stats.isDirectory()) {
process.nextTick(walkAsync, filepath, excludedDirectories, fileCallback, errback)
} else if (stats.isFile()) {
process.nextTick(fileCallback, filepath)
}
})
})
})
}
function replaceRecursively(directory, excludedDirectories, allowedExtensions, original, replacement) {
original = new RegExp(regExpQuote(original), 'g')
replacement = regExpQuoteReplacement(replacement)
const updateFile = DRY_RUN ? (filepath) => {
if (allowedExtensions.has(path.parse(filepath).ext)) {
console.log(`FILE: ${filepath}`)
} else {
console.log(`EXCLUDED:${filepath}`)
}
} : (filepath) => {
if (allowedExtensions.has(path.parse(filepath).ext)) {
sh.sed('-i', original, replacement, filepath)
}
}
walkAsync(directory, excludedDirectories, updateFile, (err) => {
console.error('ERROR while traversing directory!:')
console.error(err)
process.exit(1)
})
}
function main(args) {
if (args.length !== 2) {
console.error('USAGE: change-version old_version new_version')
console.error('Got arguments:', args)
process.exit(1)
}
const oldVersion = args[0]
const newVersion = args[1]
const EXCLUDED_DIRS = new Set([
'.git',
'node_modules',
'vendor'
])
const INCLUDED_EXTENSIONS = new Set([
// This extension whitelist is how we avoid modifying binary files
'',
'.css',
'.html',
'.js',
'.json',
'.md',
'.scss',
'.txt',
'.yml'
])
replaceRecursively('.', EXCLUDED_DIRS, INCLUDED_EXTENSIONS, oldVersion, newVersion)
}
main(process.argv.slice(2))

Binary file not shown.

View File

@@ -0,0 +1,60 @@
#!/usr/bin/env node
/*!
* Script to generate SRI hashes for use in our docs.
* Remember to use the same vendor files as the CDN ones,
* otherwise the hashes won't match!
*
* Copyright 2017-2018 The Bootstrap Authors
* Copyright 2017-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
'use strict'
const fs = require('fs')
const path = require('path')
const sriToolbox = require('sri-toolbox')
const sh = require('shelljs')
sh.config.fatal = true
const configFile = path.join(__dirname, '../_config.yml')
// Array of objects which holds the files to generate SRI hashes for.
// `file` is the path from the root folder
// `configPropertyName` is the _config.yml variable's name of the file
const files = [
{
file: 'dist/css/bootstrap.min.css',
configPropertyName: 'css_hash'
},
{
file: 'dist/js/bootstrap.min.js',
configPropertyName: 'js_hash'
},
{
file: 'site/docs/4.1/assets/js/vendor/jquery-slim.min.js',
configPropertyName: 'jquery_hash'
},
{
file: 'site/docs/4.1/assets/js/vendor/popper.min.js',
configPropertyName: 'popper_hash'
}
]
files.forEach((file) => {
fs.readFile(file.file, 'utf8', (err, data) => {
if (err) {
throw err
}
const integrity = sriToolbox.generate({
algorithms: ['sha384']
}, data)
console.log(`${file.configPropertyName}: ${integrity}`)
sh.sed('-i', new RegExp(`(\\s${file.configPropertyName}:\\s+"|')(\\S+)("|')`), `$1${integrity}$3`, configFile)
})
})

View File

@@ -0,0 +1,82 @@
#!/usr/bin/env node
/*!
* Script to find unused Sass variables.
* Copyright 2017-2018 The Bootstrap Authors
* Copyright 2017-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
'use strict'
const fs = require('fs')
const path = require('path')
const glob = require('glob')
// Blame TC39... https://github.com/benjamingr/RegExp.escape/issues/37
function regExpQuote(str) {
return str.replace(/[-\\^$*+?.()|[\]{}]/g, '\\$&')
}
let globalSuccess = true
function findUnusedVars(dir) {
if (!(fs.existsSync(dir) && fs.statSync(dir).isDirectory())) {
console.log(`"${dir}": Not a valid directory!`)
process.exit(1)
}
console.log(`Finding unused variables in "${dir}"...`)
// A variable to handle success/failure message in this function
let unusedVarsFound = false
// Array of all Sass files' content
const sassFiles = glob.sync(path.join(dir, '**/*.scss'))
// String of all Sass files' content
let sassFilesString = ''
sassFiles.forEach((file) => {
sassFilesString += fs.readFileSync(file, 'utf8')
})
// Array of all Sass variables
const variables = sassFilesString.match(/(^\$[a-zA-Z0-9_-]+[^:])/gm)
console.log(`Found ${variables.length} total variables.`)
// Loop through each variable
variables.forEach((variable) => {
const re = new RegExp(regExpQuote(variable), 'g')
const count = (sassFilesString.match(re) || []).length
if (count === 1) {
console.log(`Variable "${variable}" is not being used.`)
unusedVarsFound = true
globalSuccess = false
}
})
if (unusedVarsFound === false) {
console.log(`No unused variables found in "${dir}".`)
}
}
function main(args) {
if (args.length < 1) {
console.log('Wrong arguments!')
console.log('Usage: lint-vars.js folder [, folder2...]')
process.exit(1)
}
args.forEach((arg) => {
findUnusedVars(arg)
})
if (globalSuccess === false) {
process.exit(1)
}
}
// The first and second args are: path/to/node script.js
main(process.argv.slice(2))

View File

@@ -0,0 +1,14 @@
'use strict'
module.exports = (ctx) => ({
map: ctx.file.dirname.includes('examples') ? false : {
inline: false,
annotation: true,
sourcesContent: true
},
plugins: {
autoprefixer: {
cascade: false
}
}
})

View File

@@ -0,0 +1,53 @@
'use strict'
const path = require('path')
const babel = require('rollup-plugin-babel')
const resolve = require('rollup-plugin-node-resolve')
const pkg = require(path.resolve(__dirname, '../package.json'))
const BUNDLE = process.env.BUNDLE === 'true'
const year = new Date().getFullYear()
let fileDest = 'bootstrap.js'
const external = ['jquery', 'popper.js']
const plugins = [
babel({
exclude: 'node_modules/**', // Only transpile our source code
externalHelpersWhitelist: [ // Include only required helpers
'defineProperties',
'createClass',
'inheritsLoose',
'defineProperty',
'objectSpread'
]
})
]
const globals = {
jquery: 'jQuery', // Ensure we use jQuery which is always available even in noConflict mode
'popper.js': 'Popper'
}
if (BUNDLE) {
fileDest = 'bootstrap.bundle.js'
// Remove last entry in external array to bundle Popper
external.pop()
delete globals['popper.js']
plugins.push(resolve())
}
module.exports = {
input: path.resolve(__dirname, '../js/src/index.js'),
output: {
banner: `/*!
* Bootstrap v${pkg.version} (${pkg.homepage})
* Copyright 2011-${year} ${pkg.author}
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/`,
file: path.resolve(__dirname, `../dist/js/${fileDest}`),
format: 'umd',
globals,
name: 'bootstrap'
},
external,
plugins
}

View File

@@ -0,0 +1,65 @@
[
{
"browserName": "safari",
"platform": "OS X 10.11",
"version": "latest"
},
{
"browserName": "chrome",
"platform": "OS X 10.11",
"version": "latest"
},
{
"browserName": "firefox",
"platform": "OS X 10.11",
"version": "latest"
},
{
"browserName": "MicrosoftEdge",
"platform": "Windows 10",
"version": "latest"
},
{
"browserName": "internet explorer",
"version": "11",
"platform": "Windows 8.1"
},
{
"browserName": "internet explorer",
"version": "10",
"platform": "Windows 8"
},
{
"browserName": "chrome",
"platform": "Windows 10",
"version": "latest"
},
{
"browserName": "firefox",
"platform": "Windows 10",
"version": "latest"
},
{
"browserName": "iphone",
"deviceName": "iPhone Simulator",
"platformName": "OS X 10.11",
"version": "9.3"
},
{
"browserName": "chrome",
"platform": "Linux",
"version": "latest"
},
{
"browserName": "firefox",
"platform": "Linux",
"version": "latest"
},
{
"platform": "Linux",
"browserName": "android",
"deviceName": "Android Emulator",
"version": "latest",
"deviceType": "phone"
}
]

View File

@@ -0,0 +1,116 @@
/*!
* Script to run our Sauce Labs tests.
* Copyright 2017-2018 The Bootstrap Authors
* Copyright 2017-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
/*
Docs: https://wiki.saucelabs.com/display/DOCS/Platform+Configurator
Mac Opera is not currently supported by Sauce Labs
Win Opera 15+ is not currently supported by Sauce Labs
iOS Chrome is not currently supported by Sauce Labs
*/
'use strict'
const path = require('path')
const JSUnitSaucelabs = require('jsunitsaucelabs')
const jsUnitSaucelabs = new JSUnitSaucelabs({
username: process.env.SAUCE_USERNAME,
password: process.env.SAUCE_ACCESS_KEY,
build: process.env.TRAVIS_JOB_ID
})
const testURL = 'http://localhost:3000/js/tests/index.html?hidepassed'
const browsersFile = require(path.resolve(__dirname, './sauce_browsers.json'))
const errorMessages = [
'Test exceeded maximum duration',
'Test exceeded maximum duration after 180 seconds'
]
let jobsDone = 0
let jobsSucceeded = 0
const waitingCallback = (error, body, id) => {
if (error) {
console.error(error)
process.exit(1)
}
if (typeof body !== 'undefined') {
if (!body.completed) {
setTimeout(() => {
jsUnitSaucelabs.getStatus(id, (error, body) => {
waitingCallback(error, body, id)
})
}, 2000)
} else {
const test = body['js tests'][0]
const platform = test.platform.join(', ')
let passed = false
let errorStr = false
if (test.result !== null) {
if (typeof test.result === 'string' && errorMessages.includes(test.result)) {
errorStr = test.result
} else {
passed = test.result.total === test.result.passed
}
}
console.log(`Tested ${testURL}`)
console.log(`Platform: ${platform}`)
console.log(`Passed: ${passed}`)
console.log(`URL: ${test.url}\n`)
if (errorStr) {
console.error(`${platform}: ${errorStr}`)
}
if (passed) {
jobsSucceeded++
}
jobsDone++
// Exit
if (jobsDone === browsersFile.length - 1) {
jsUnitSaucelabs.stop()
if (jobsDone > jobsSucceeded) {
const failedTests = jobsDone - jobsSucceeded
throw new Error(`${failedTests} test${failedTests > 1 ? 's' : ''} failed.`)
}
console.log('All tests passed')
process.exit(0)
}
}
}
}
jsUnitSaucelabs.on('tunnelCreated', () => {
browsersFile.forEach((tmpBrowser) => {
const browsersPlatform = typeof tmpBrowser.platform === 'undefined' ? tmpBrowser.platformName : tmpBrowser.platform
const browsersArray = [browsersPlatform, tmpBrowser.browserName, tmpBrowser.version]
jsUnitSaucelabs.start([browsersArray], testURL, 'qunit', (error, success) => {
if (typeof success !== 'undefined') {
const taskIds = success['js tests']
if (!taskIds || taskIds.length === 0) {
throw new Error('Error starting tests through Sauce Labs API')
}
taskIds.forEach((id) => {
jsUnitSaucelabs.getStatus(id, (error, body) => {
waitingCallback(error, body, id)
})
})
} else {
console.error(error)
}
})
})
})
jsUnitSaucelabs.initTunnel()

View File

@@ -0,0 +1,70 @@
#!/usr/bin/env bash
#
# Usage
# ---------------
# 1. Clone second version of Bootstrap in sibling directory named `bs-docs`.
# 2. Within `bs-docs` copy, switch to `gh-pages` branch.
# 3. Pull latest, re-bundle, re-npm.
# 4. Run script.
red=$'\e[1;31m'
green=$'\e[1;32m'
#blue=$'\e[1;34m'
magenta=$'\e[1;35m'
#cyan=$'\e[1;36m'
end=$'\e[0m'
# Get current version from package.json
current_version=$(node -p "require('./package.json').version")
if [[ $# -lt 1 ]]; then
printf "\n%s⚠ Shipping aborted. You must specify a version.\n%s" $red $end
exit 1
fi
# Pulling latest changes, just to be sure
printf "\n%s=======================================================%s" $magenta $end
printf "\n%sPulling latest changes...%s" $magenta $end
printf "\n%s=======================================================\n\n%s" $magenta $end
git pull origin v4-dev
# Update version number
printf "\n%s=======================================================%s" $magenta $end
printf "\n%sUpdating version number...%s" $magenta $end
printf "\n%s=======================================================\n%s" $magenta $end
npm run release-version "$current_version" "$1"
# Compile latest CSS and JS
printf "\n%s=======================================================%s" $magenta $end
printf "\n%sCompile latest CSS and JS...%s" $magenta $end
printf "\n%s=======================================================\n%s" $magenta $end
npm run dist
# Generate the SRI hashes
printf "\n%s=======================================================%s" $magenta $end
printf "\n%sGenerate the SRI hashes...%s" $magenta $end
printf "\n%s=======================================================\n%s" $magenta $end
npm run release-sri
# Compress the dist files
printf "\n%s=======================================================%s" $magenta $end
printf "\n%sCompressing the dist files...%s" $magenta $end
printf "\n%s=======================================================\n%s" $magenta $end
npm run release-zip
# Compile the docs
printf "\n%s=======================================================%s" $magenta $end
printf "\n%sCompile hosted documentation...%s" $magenta $end
printf "\n%s=======================================================\n%s" $magenta $end
npm run docs-github
# Copy the contents of the built docs site over to `bs-docs` repo
printf "\n%s=======================================================%s" $magenta $end
printf "\n%sCopy it over...%s" $magenta $end
printf "\n%s=======================================================\n%s" $magenta $end
cp -rf _gh_pages/. ../bs-docs/
printf "\nDone!\n"
printf "\n%s=======================================================%s" $green $end
printf "\n%sSuccess, $1 is ready to review and publish.%s" $green $end
printf "\n%s=======================================================\n\n%s" $green $end

View File

@@ -0,0 +1,68 @@
#!/usr/bin/env node
/*!
* Script to run vnu-jar if Java is available.
* Copyright 2017-2018 The Bootstrap Authors
* Copyright 2017-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
'use strict'
const childProcess = require('child_process')
const vnu = require('vnu-jar')
childProcess.exec('java -version', (error, stdout, stderr) => {
if (error) {
console.error('Skipping vnu-jar test; Java is missing.')
return
}
const is32bitJava = !stderr.match(/64-Bit/)
// vnu-jar accepts multiple ignores joined with a `|`.
// Also note that the ignores are regular expressions.
const ignores = [
// "autocomplete" is included in <button> and checkboxes and radio <input>s due to
// Firefox's non-standard autocomplete behavior - see https://bugzilla.mozilla.org/show_bug.cgi?id=654072
'Attribute “autocomplete” is only allowed when the input type is.*',
'Attribute “autocomplete” not allowed on element “button” at this point.',
// We use holder.js with `data-src` and no `src` to avoid 404 errors;
// we could work around this, but I'm not sure it's worth it.
'Element “img” is missing required attribute “src”.',
// Markup used in Components → Forms → Layout → Form grid → Horizontal form is currently invalid,
// but used this way due to lack of support for flexbox layout on <fieldset> element in most browsers
'Element “legend” not allowed as child of element “div” in this context.*',
// Content → Reboot uses various date/time inputs as a visual example.
// Documentation does not rely on them being usable.
'The “date” input type is not supported in all browsers.*',
'The “time” input type is not supported in all browsers.*',
// IE11 doesn't recognise <main> / give the element an implicit "main" landmark.
// Explicit role="main" is redundant for other modern browsers, but still valid.
'The “main” role is unnecessary for element “main”.',
// Ignore the wrong lanuage code warnings for now; they happen randomly.
'This document appears to be written in.*'
].join('|')
const args = [
'-jar',
vnu,
'--asciiquotes',
'--skip-non-html',
'--Werror',
`--filterpattern "${ignores}"`,
'_gh_pages/',
'js/tests/'
]
// For the 32-bit Java we need to pass `-Xss512k`
if (is32bitJava) {
args.splice(0, 0, '-Xss512k')
}
return childProcess.spawn('java', args, {
shell: true,
stdio: 'inherit'
})
.on('exit', process.exit)
})

View File

@@ -0,0 +1,8 @@
{
"globDirectory": "./",
"globPatterns": [
"_gh_pages/**/*.{html,css,js,json,png,svg}"
],
"swSrc": "./site/sw.js",
"swDest": "./_gh_pages/sw.js"
}

View File

@@ -0,0 +1,58 @@
/*!
* Script to generate our docs service worker.
* Copyright 2017-2018 The Bootstrap Authors
* Copyright 2017-2018 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
'use strict'
const fs = require('fs')
const path = require('path')
const swBuild = require('workbox-build')
const config = require('./workbox.config.json')
const buildPrefix = '_gh_pages/'
const workboxSWSrcPath = require.resolve('workbox-sw')
const wbFileName = path.basename(workboxSWSrcPath)
const workboxSWDestPath = `${buildPrefix}docs/4.1/assets/js/vendor/${wbFileName}`
const workboxSWSrcMapPath = `${workboxSWSrcPath}.map`
const workboxSWDestMapPath = `${workboxSWDestPath}.map`
fs.createReadStream(workboxSWSrcPath).pipe(fs.createWriteStream(workboxSWDestPath))
fs.createReadStream(workboxSWSrcMapPath).pipe(fs.createWriteStream(workboxSWDestMapPath))
const updateUrl = (manifestEntries) => {
const manifest = manifestEntries.map((entry) => {
if (entry.url.startsWith(buildPrefix)) {
const regex = new RegExp(buildPrefix, 'g')
entry.url = entry.url.replace(regex, '')
}
return entry
})
return {
manifest,
warnings: []
}
}
config.manifestTransforms = [updateUrl]
swBuild.injectManifest(config).then(({
count,
size
}) => {
const wbSwRegex = /{fileName}/g
fs.readFile(config.swDest, 'utf8', (err, data) => {
if (err) {
throw err
}
const swFileContents = data.replace(wbSwRegex, wbFileName)
fs.writeFile(config.swDest, swFileContents, () => {
console.log(`Pre-cache Manifest generated. Pre-cached ${count} files, totalling ${size} bytes.`)
})
})
}).catch((error) => {
console.error(`Something went wrong: ${error}`)
})