diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index fbb99eec31..751ec4914d 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -4,5 +4,6 @@ # The last matching pattern takes precedence. # https://help.github.com/articles/about-codeowners/ -* @spotify/backstage-core -/plugins/techdocs @spotify/techdocs-core +* @spotify/backstage-core +/plugins/techdocs @spotify/techdocs-core +/packages/techdocs-cli @spotify/techdocs-core diff --git a/ADOPTERS.md b/ADOPTERS.md new file mode 100644 index 0000000000..d0f8c0a97b --- /dev/null +++ b/ADOPTERS.md @@ -0,0 +1,3 @@ +| Organization | Contact | Description of Use | +| ------------ | ------- | ------------------ | +| [Spotify](https://www.spotify.com) |[@alund](https://github.com/alund)| Main interface towards all of Spotify's infrastructure and technical documentation.| diff --git a/packages/app/src/index.tsx b/packages/app/src/index.tsx index 2ea8d3f1dd..a38159a258 100644 --- a/packages/app/src/index.tsx +++ b/packages/app/src/index.tsx @@ -14,6 +14,8 @@ * limitations under the License. */ +// eslint-disable-next-line monorepo/no-internal-import +import '@backstage/cli/asset-types'; import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; diff --git a/packages/backend/src/plugins/scaffolder.ts b/packages/backend/src/plugins/scaffolder.ts index ce3a7ea2bd..95d28eacb1 100644 --- a/packages/backend/src/plugins/scaffolder.ts +++ b/packages/backend/src/plugins/scaffolder.ts @@ -18,6 +18,7 @@ import { CookieCutter, createRouter, FilePreparer, + GithubPreparer, Preparers, } from '@backstage/plugin-scaffolder-backend'; import type { PluginEnvironment } from '../types'; @@ -25,9 +26,11 @@ import type { PluginEnvironment } from '../types'; export default async function createPlugin({ logger }: PluginEnvironment) { const templater = new CookieCutter(); const filePreparer = new FilePreparer(); + const githubPreparer = new GithubPreparer(); const preparers = new Preparers(); preparers.register('file', filePreparer); + preparers.register('github', githubPreparer); return await createRouter({ preparers, templater, logger }); } diff --git a/packages/cli/src/commands/plugin/assets.d.ts b/packages/cli/asset-types/asset-types.d.ts similarity index 83% rename from packages/cli/src/commands/plugin/assets.d.ts rename to packages/cli/asset-types/asset-types.d.ts index 34bb6acb70..1763d256f5 100644 --- a/packages/cli/src/commands/plugin/assets.d.ts +++ b/packages/cli/asset-types/asset-types.d.ts @@ -14,16 +14,12 @@ * limitations under the License. */ +/* eslint-disable import/no-extraneous-dependencies */ + /// /// /// -declare namespace NodeJS { - interface ProcessEnv { - readonly NODE_ENV: 'development' | 'production' | 'test'; - } -} - declare module '*.bmp' { const src: string; export default src; @@ -54,13 +50,15 @@ declare module '*.webp' { export default src; } +declare module '*.icon.svg' { + import { ComponentType } from 'react'; + import { SvgIconProps } from '@material-ui/core'; + + const Icon: ComponentType; + export default Icon; +} + declare module '*.svg' { - import * as React from 'react'; - - export const ReactComponent: React.FunctionComponent & { title?: string }>; - const src: string; export default src; } @@ -94,7 +92,3 @@ declare module '*.module.sass' { const classes: { readonly [key: string]: string }; export default classes; } - -declare module 'rollup-plugin-image-files' { - export default function image(): any; -} diff --git a/packages/cli/asset-types/asset-types.js b/packages/cli/asset-types/asset-types.js new file mode 100644 index 0000000000..65ef751860 --- /dev/null +++ b/packages/cli/asset-types/asset-types.js @@ -0,0 +1,2 @@ +// NOOP, this is just here to unbreak module resolution +// eslint-disable-next-line notice/notice diff --git a/packages/cli/asset-types/package.json b/packages/cli/asset-types/package.json new file mode 100644 index 0000000000..ffa5e09fc1 --- /dev/null +++ b/packages/cli/asset-types/package.json @@ -0,0 +1,5 @@ +{ + "main": "asset-types.js", + "types": "asset-types.d.ts", + "description": "Provides types for asset files that are handled by the Backstage CLI" +} diff --git a/packages/cli/config/jest.js b/packages/cli/config/jest.js index ad24976ad0..80e0bcf26c 100644 --- a/packages/cli/config/jest.js +++ b/packages/cli/config/jest.js @@ -38,11 +38,16 @@ async function getConfig() { transform: { '\\.esm\\.js$': require.resolve('jest-esm-transformer'), '\\.(js|jsx|ts|tsx)': require.resolve('ts-jest'), + '\\.(bmp|gif|jpe|png|frag|xml|svg)': require.resolve( + './jestFileTransform.js', + ), }, // Default behaviour is to not apply transforms for node_modules, but we still want // to apply the esm-transformer to .esm.js files, since that's what we use in backstage packages. - transformIgnorePatterns: ['/node_modules/(?!.*\\.esm\\.js$)'], + transformIgnorePatterns: [ + '/node_modules/(?!.*\\.(?:esm\\.js|bmp|gif|jpe|png|frag|xml|svg)$)', + ], }; // Use src/setupTests.ts as the default location for configuring test env diff --git a/packages/cli/config/jestFileTransform.js b/packages/cli/config/jestFileTransform.js new file mode 100644 index 0000000000..e6ff1895f8 --- /dev/null +++ b/packages/cli/config/jestFileTransform.js @@ -0,0 +1,42 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const path = require('path'); + +module.exports = { + process(src, filename) { + const assetFilename = JSON.stringify(path.basename(filename)); + + if (filename.match(/\.icon\.svg$/)) { + return `const React = require('react'); + const SvgIcon = require('@material-ui/core/SvgIcon').default; + module.exports = { + __esModule: true, + default: props => React.createElement(SvgIcon, props, { + $$typeof: Symbol.for('react.element'), + type: 'svg', + ref: ref, + key: null, + props: Object.assign({}, props, { + children: ${assetFilename} + }) + }) + };`; + } + + return `module.exports = ${assetFilename};`; + }, +}; diff --git a/packages/cli/package.json b/packages/cli/package.json index 96ca8e4a4f..66828e9dec 100644 --- a/packages/cli/package.json +++ b/packages/cli/package.json @@ -39,6 +39,10 @@ "@rollup/plugin-node-resolve": "^7.1.1", "@spotify/eslint-config": "^7.0.1", "@sucrase/webpack-loader": "^2.0.0", + "@svgr/plugin-jsx": "4.3.x", + "@svgr/plugin-svgo": "4.3.x", + "@svgr/rollup": "4.3.x", + "@svgr/webpack": "4.3.x", "@types/start-server-webpack-plugin": "^2.2.0", "@types/webpack-env": "^1.15.2", "@types/webpack-node-externals": "^1.7.1", diff --git a/packages/cli/src/lib/bundler/transforms.ts b/packages/cli/src/lib/bundler/transforms.ts index 0cd800f2ea..5f881bd53c 100644 --- a/packages/cli/src/lib/bundler/transforms.ts +++ b/packages/cli/src/lib/bundler/transforms.ts @@ -17,6 +17,7 @@ import webpack, { Module, Plugin } from 'webpack'; import MiniCssExtractPlugin from 'mini-css-extract-plugin'; import { BundlingOptions, BackendBundlingOptions } from './types'; +import { svgrTemplate } from '../svgrTemplate'; type Transforms = { loaders: Module['rules']; @@ -46,7 +47,28 @@ export const transforms = ( }, }, { - test: [/\.bmp$/, /\.gif$/, /\.jpe?g$/, /\.png$/, /\.frag/, /\.xml/], + test: [/\.icon\.svg$/], + use: [ + { + loader: require.resolve('@sucrase/webpack-loader'), + options: { transforms: ['jsx'] }, + }, + { + loader: require.resolve('@svgr/webpack'), + options: { babel: false, template: svgrTemplate }, + }, + ], + }, + { + test: [ + /\.bmp$/, + /\.gif$/, + /\.jpe?g$/, + /\.png$/, + /\.frag/, + { test: /\.svg/, not: [/\.icon\.svg/] }, + /\.xml/, + ], loader: require.resolve('url-loader'), options: { limit: 10000, diff --git a/packages/cli/src/lib/packager/config.ts b/packages/cli/src/lib/packager/config.ts index 30680ef3b9..5987290604 100644 --- a/packages/cli/src/lib/packager/config.ts +++ b/packages/cli/src/lib/packager/config.ts @@ -23,12 +23,14 @@ import resolve from '@rollup/plugin-node-resolve'; import postcss from 'rollup-plugin-postcss'; import esbuild from 'rollup-plugin-esbuild'; import imageFiles from 'rollup-plugin-image-files'; +import svgr from '@svgr/rollup'; import dts from 'rollup-plugin-dts'; import json from '@rollup/plugin-json'; import { RollupOptions, OutputOptions } from 'rollup'; import { BuildOptions, Output } from './types'; import { paths } from '../paths'; +import { svgrTemplate } from '../svgrTemplate'; export const makeConfigs = async ( options: BuildOptions, @@ -89,8 +91,12 @@ export const makeConfigs = async ( exclude: ['**/*.stories.*', '**/*.test.*'], }), postcss(), - imageFiles(), + imageFiles({ exclude: '**/*.icon.svg' }), json(), + svgr({ + include: '**/*.icon.svg', + template: svgrTemplate, + }), esbuild({ target: 'es2019', }), diff --git a/packages/cli/src/lib/svgrTemplate.ts b/packages/cli/src/lib/svgrTemplate.ts new file mode 100644 index 0000000000..5f7c7f9a4c --- /dev/null +++ b/packages/cli/src/lib/svgrTemplate.ts @@ -0,0 +1,47 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/** + * This template, together with loaders in the bundler and packages, allows + * for SVG to be imported directly as MUI SvgIcon components by suffixing + * them with .icon.svg + */ +export function svgrTemplate( + { template }: any, + _opts: any, + { imports, interfaces, componentName, jsx }: any, +) { + const iconName = { + ...componentName, + name: `${componentName.name.replace(/icon$/, '')}Icon`, + }; + + const defaultExport = { + type: 'ExportDefaultDeclaration', + declaration: iconName, + }; + + const typeScriptTemplate = template.smart({ plugins: ['typescript'] }); + return typeScriptTemplate.ast` +${imports} +import SvgIcon from '@material-ui/core/SvgIcon'; + +${interfaces} + +const ${iconName} = props => React.createElement(SvgIcon, props, ${jsx.children}); + +${defaultExport}`; +} diff --git a/packages/cli/src/types.d.ts b/packages/cli/src/types.d.ts new file mode 100644 index 0000000000..8cb5a1e7df --- /dev/null +++ b/packages/cli/src/types.d.ts @@ -0,0 +1,29 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +declare namespace NodeJS { + interface ProcessEnv { + readonly NODE_ENV: 'development' | 'production' | 'test'; + } +} + +declare module 'rollup-plugin-image-files' { + export default function image(options?: any): any; +} + +declare module '@svgr/rollup' { + export default function svgr(options?: any): any; +} diff --git a/packages/cli/templates/default-app/packages/app/src/index.tsx b/packages/cli/templates/default-app/packages/app/src/index.tsx index b597a44232..b16aaf7cd2 100644 --- a/packages/cli/templates/default-app/packages/app/src/index.tsx +++ b/packages/cli/templates/default-app/packages/app/src/index.tsx @@ -1,3 +1,4 @@ +import '@backstage/cli/asset-types'; import React from 'react'; import ReactDOM from 'react-dom'; import App from './App'; diff --git a/packages/core/src/layout/ErrorPage/MicDrop.jsx b/packages/core/src/layout/ErrorPage/MicDrop.jsx index 4c4098f486..ca0a0ae0a6 100644 --- a/packages/core/src/layout/ErrorPage/MicDrop.jsx +++ b/packages/core/src/layout/ErrorPage/MicDrop.jsx @@ -16,6 +16,7 @@ import React from 'react'; import { makeStyles } from '@material-ui/core'; +import MicDropSvgUrl from './mic-drop.svg'; const useStyles = makeStyles({ micDrop: { @@ -28,133 +29,5 @@ const useStyles = makeStyles({ export const MicDrop = () => { const classes = useStyles(); - return ( - - - - - - - - - - - - - - - - - - - - - - ); + return ; }; diff --git a/packages/core/src/layout/ErrorPage/mic-drop.svg b/packages/core/src/layout/ErrorPage/mic-drop.svg new file mode 100644 index 0000000000..adc027b551 --- /dev/null +++ b/packages/core/src/layout/ErrorPage/mic-drop.svg @@ -0,0 +1,126 @@ + + + + + + + + + + + + + + + + + + + + + diff --git a/packages/techdocs-cli/.eslintrc.js b/packages/techdocs-cli/.eslintrc.js new file mode 100644 index 0000000000..13573efa9c --- /dev/null +++ b/packages/techdocs-cli/.eslintrc.js @@ -0,0 +1,3 @@ +module.exports = { + extends: [require.resolve('@backstage/cli/config/eslint')], +}; diff --git a/packages/techdocs-cli/README.md b/packages/techdocs-cli/README.md new file mode 100644 index 0000000000..d7c17210bd --- /dev/null +++ b/packages/techdocs-cli/README.md @@ -0,0 +1,5 @@ +# TechDocs CLI + +Check out the [TechDocs README](https://github.com/spotify/backstage/blob/master/plugins/techdocs/README.md) to learn more. + +**WIP: This cli is a work in progress. It is not ready for use yet. Follow our progress on [the Backstage Discord](https://discord.gg/MUpMjP2) under #docs-like-code or on [our GitHub Milestone](https://github.com/spotify/backstage/milestone/15).** diff --git a/packages/techdocs-cli/bin/techdocs-cli b/packages/techdocs-cli/bin/techdocs-cli new file mode 100755 index 0000000000..8581750373 --- /dev/null +++ b/packages/techdocs-cli/bin/techdocs-cli @@ -0,0 +1,34 @@ +#!/usr/bin/env node +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const path = require('path'); + +// Figure out whether we're running inside the backstage repo or as an installed dependency +const isLocal = require('fs').existsSync(path.resolve(__dirname, '../src')); + +if (!isLocal) { + require('..'); +} else { + require('ts-node').register({ + transpileOnly: true, + compilerOptions: { + module: 'CommonJS', + }, + }); + + require('../src'); +} diff --git a/packages/techdocs-cli/package.json b/packages/techdocs-cli/package.json new file mode 100644 index 0000000000..927d9477d8 --- /dev/null +++ b/packages/techdocs-cli/package.json @@ -0,0 +1,42 @@ +{ + "name": "@backstage/techdocs-cli", + "description": "CLI for running TechDocs locally.", + "version": "0.1.1-alpha.9", + "private": true, + "publishConfig": { + "access": "public" + }, + "repository": { + "type": "git", + "url": "https://github.com/spotify/backstage", + "directory": "packages/techdocs-cli" + }, + "keywords": [ + "backstage", + "techdocs" + ], + "license": "Apache-2.0", + "main": "dist/index.cjs.js", + "scripts": { + "build": "backstage-cli build --outputs cjs", + "lint": "backstage-cli lint", + "test": "backstage-cli test --passWithNoTests", + "clean": "backstage-cli clean", + "start": "nodemon --" + }, + "bin": { + "techdocs": "bin/techdocs-cli" + }, + "devDependencies": { + "@backstage/cli": "^0.1.1-alpha.9" + }, + "files": [ + "bin", + "dist/**/*.js" + ], + "nodemonConfig": { + "watch": "./src", + "exec": "bin/techdocs-cli", + "ext": "ts" + } +} diff --git a/packages/cli/@types/rollup-plugin-image-files.d.ts b/packages/techdocs-cli/src/index.ts similarity index 93% rename from packages/cli/@types/rollup-plugin-image-files.d.ts rename to packages/techdocs-cli/src/index.ts index 9ddc2c2351..a010f4bfe5 100644 --- a/packages/cli/@types/rollup-plugin-image-files.d.ts +++ b/packages/techdocs-cli/src/index.ts @@ -14,4 +14,4 @@ * limitations under the License. */ -declare module 'rollup-plugin-image-files'; +export const techDocsCli = () => {}; diff --git a/plugins/catalog/src/components/EntityPage/EntityPage.test.tsx b/plugins/catalog/src/components/EntityPage/EntityPage.test.tsx index aeb9fc543b..e6064f8af1 100644 --- a/plugins/catalog/src/components/EntityPage/EntityPage.test.tsx +++ b/plugins/catalog/src/components/EntityPage/EntityPage.test.tsx @@ -25,11 +25,13 @@ jest.mock('react-router-dom', () => { }); import { ApiProvider, ApiRegistry, errorApiRef } from '@backstage/core'; +import { Entity } from '@backstage/catalog-model'; import { wrapInTestApp } from '@backstage/test-utils'; import { render, wait } from '@testing-library/react'; import * as React from 'react'; import { CatalogApi, catalogApiRef } from '../../api/types'; -import { EntityPage } from './EntityPage'; +import { EntityPage, getPageTheme } from './EntityPage'; + const { useParams, useNavigate, @@ -67,3 +69,32 @@ describe('EntityPage', () => { await wait(() => expect(useNavigate()).toHaveBeenCalledWith('/catalog')); }); }); + +describe('getPageTheme', () => { + const defaultPageTheme = getPageTheme(); + it.each(['service', 'app', 'library', 'tool', 'documentation', 'website'])( + 'should select right theme for predefined type: %p ̰ ', + type => { + const theme = getPageTheme(({ + spec: { + type, + }, + } as any) as Entity); + expect(theme).toBeDefined(); + expect(theme).not.toBe(defaultPageTheme); + }, + ); + + it('should select default theme for unknown/unspecified types', () => { + const theme1 = getPageTheme(({ + spec: { + type: 'unknown-type', + }, + } as any) as Entity); + const theme2 = getPageTheme(({ + spec: {}, + } as any) as Entity); + expect(theme1).toBe(defaultPageTheme); + expect(theme2).toBe(defaultPageTheme); + }); +}); diff --git a/plugins/catalog/src/components/EntityPage/EntityPage.tsx b/plugins/catalog/src/components/EntityPage/EntityPage.tsx index d9953498ec..f57e470e57 100644 --- a/plugins/catalog/src/components/EntityPage/EntityPage.tsx +++ b/plugins/catalog/src/components/EntityPage/EntityPage.tsx @@ -24,6 +24,7 @@ import { pageTheme, Progress, useApi, + PageTheme, } from '@backstage/core'; import { SentryIssuesWidget } from '@backstage/plugin-sentry'; import { Grid } from '@material-ui/core'; @@ -56,6 +57,11 @@ function headerProps( }; } +export const getPageTheme = (entity?: Entity): PageTheme => { + const themeKey = entity?.spec?.type?.toString() ?? 'home'; + return pageTheme[themeKey] ?? pageTheme.home; +}; + export const EntityPage: FC<{}> = () => { const { optionalNamespaceAndName, kind } = useParams() as { optionalNamespaceAndName: string; @@ -130,8 +136,7 @@ export const EntityPage: FC<{}> = () => { ); return ( - // TODO: Switch theme and type props based on component type (website, library, ...) - +
{entity && }
diff --git a/plugins/catalog/src/data/filters.ts b/plugins/catalog/src/data/filters.ts index c13f1a2d9c..51ed5582f5 100644 --- a/plugins/catalog/src/data/filters.ts +++ b/plugins/catalog/src/data/filters.ts @@ -90,7 +90,7 @@ export const entityFilters: Record = { export const entityTypeFilter = (e: Entity, type: string) => (e.spec as any)?.type === type; -type EntityType = 'service' | 'website' | 'lib' | 'documentation' | 'other'; +type EntityType = 'service' | 'website' | 'library' | 'documentation' | 'other'; type LabeledEntityType = { id: EntityType; @@ -107,7 +107,7 @@ export const labeledEntityTypes: LabeledEntityType[] = [ label: 'Websites', }, { - id: 'lib', + id: 'library', label: 'Libraries', }, { diff --git a/plugins/graphiql/src/assets/graphiql.icon.svg b/plugins/graphiql/src/assets/graphiql.icon.svg new file mode 100644 index 0000000000..66aee7be5a --- /dev/null +++ b/plugins/graphiql/src/assets/graphiql.icon.svg @@ -0,0 +1,64 @@ + + + + + + + + + + + + + + + + + + + diff --git a/plugins/graphiql/src/route-refs.tsx b/plugins/graphiql/src/route-refs.tsx index 5ddd81d55d..3e8d1d3a9c 100644 --- a/plugins/graphiql/src/route-refs.tsx +++ b/plugins/graphiql/src/route-refs.tsx @@ -14,76 +14,8 @@ * limitations under the License. */ -import React, { FC } from 'react'; import { createRouteRef } from '@backstage/core'; -import { SvgIcon, SvgIconProps } from '@material-ui/core'; - -const GraphiQLIcon: FC = props => ( - - - - - - - - - - - - - - - - - - - -); +import GraphiQLIcon from './assets/graphiql.icon.svg'; export const graphiQLRouteRef = createRouteRef({ icon: GraphiQLIcon, diff --git a/plugins/scaffolder-backend/package.json b/plugins/scaffolder-backend/package.json index b356f026e5..0d99ad6053 100644 --- a/plugins/scaffolder-backend/package.json +++ b/plugins/scaffolder-backend/package.json @@ -31,15 +31,19 @@ "express": "^4.17.1", "express-promise-router": "^3.0.3", "fs-extra": "^9.0.0", + "git-url-parse": "^11.1.2", "globby": "^11.0.0", "helmet": "^3.22.0", "morgan": "^1.10.0", + "nodegit": "0.26.5", "winston": "^3.2.1" }, "devDependencies": { "@backstage/cli": "^0.1.1-alpha.9", "@types/dockerode": "^2.5.32", "@types/fs-extra": "^9.0.1", + "@types/git-url-parse": "^9.0.0", + "@types/nodegit": "0.26.5", "@types/supertest": "^2.0.8", "supertest": "^4.0.2", "yaml": "^1.10.0" diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts new file mode 100644 index 0000000000..44d53248d0 --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/github.test.ts @@ -0,0 +1,85 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +const mocks = { + Clone: { clone: jest.fn() }, + CheckoutOptions: jest.fn(() => {}), +}; +jest.doMock('nodegit', () => mocks); +// require('nodegit'); + +import { GithubPreparer } from './github'; +import { + TemplateEntityV1alpha1, + LOCATION_ANNOTATION, +} from '@backstage/catalog-model'; + +describe('GitHubPreparer', () => { + let mockEntity: TemplateEntityV1alpha1; + beforeEach(() => { + jest.clearAllMocks(); + mockEntity = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: + 'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + }); + it('calls the clone command with the correct arguments for a repository', async () => { + const preparer = new GithubPreparer(); + await preparer.prepare(mockEntity); + expect(mocks.Clone.clone).toHaveBeenNthCalledWith( + 1, + 'https://github.com/benjdlambert/backstage-graphql-template', + expect.any(String), + { checkoutOpts: { paths: ['template'] } }, + ); + }); + it('calls the clone command with the correct arguments for a repository when no path is provided', async () => { + const preparer = new GithubPreparer(); + delete mockEntity.spec.path; + await preparer.prepare(mockEntity); + expect(mocks.Clone.clone).toHaveBeenNthCalledWith( + 1, + 'https://github.com/benjdlambert/backstage-graphql-template', + expect.any(String), + { checkoutOpts: {} }, + ); + }); + + it('return the temp directory with the path to the folder if it is specified', async () => { + const preparer = new GithubPreparer(); + mockEntity.spec.path = './template/test/1/2/3'; + const response = await preparer.prepare(mockEntity); + + expect(response).toMatch(new RegExp(/\/template\/test\/1\/2\/3$/)); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts new file mode 100644 index 0000000000..b0ced7db2b --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/github.ts @@ -0,0 +1,60 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import fs from 'fs-extra'; +import path from 'path'; +import os from 'os'; +import { TemplateEntityV1alpha1 } from '@backstage/catalog-model'; +import { parseLocationAnnotation } from './helpers'; +import { InputError } from '@backstage/backend-common'; +import { PreparerBase } from './types'; +import GitUriParser from 'git-url-parse'; +import { Clone, CheckoutOptions } from 'nodegit'; + +export class GithubPreparer implements PreparerBase { + async prepare(template: TemplateEntityV1alpha1): Promise { + const { protocol, location } = parseLocationAnnotation(template); + + if (protocol !== 'github') { + throw new InputError( + `Wrong location protocol: ${protocol}, should be 'github'`, + ); + } + const templateId = template.metadata.name; + + const parsedGitLocation = GitUriParser(location); + const repositoryCheckoutUrl = parsedGitLocation.toString('https'); + const tempDir = await fs.promises.mkdtemp( + path.join(os.tmpdir(), templateId), + ); + + const templateDirectory = path.join( + `${path.dirname(parsedGitLocation.filepath)}`, + template.spec.path ?? '.', + ); + + const checkoutOptions = new CheckoutOptions(); + if (template.spec.path) { + checkoutOptions.paths = [templateDirectory]; + } + + await Clone.clone(repositoryCheckoutUrl, tempDir, { + checkoutOpts: checkoutOptions, + // TODO(blam): Maybe need some auth here? + }); + + return path.resolve(tempDir, templateDirectory); + } +} diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/helpers.test.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/helpers.test.ts new file mode 100644 index 0000000000..6aa940783f --- /dev/null +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/helpers.test.ts @@ -0,0 +1,171 @@ +/* + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +import { parseLocationAnnotation } from './helpers'; +import { + TemplateEntityV1alpha1, + LOCATION_ANNOTATION, +} from '@backstage/catalog-model'; + +describe('Helpers', () => { + describe('parseLocationAnnotation', () => { + it('throws an exception when no annotation location', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + // [LOCATION_ANNOTATION]: + // 'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(() => parseLocationAnnotation(mockEntity)).toThrow( + expect.objectContaining({ + name: 'InputError', + message: `No location annotation provided in entity: ${mockEntity.metadata.name}`, + }), + ); + }); + + it('should throw an error when the protocol part is not set in the location annotation', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: + ':https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(() => parseLocationAnnotation(mockEntity)).toThrow( + expect.objectContaining({ + name: 'InputError', + message: `Failure to parse either protocol or location for entity: ${mockEntity.metadata.name}`, + }), + ); + }); + it('should throw an error when the location part is not set in the location annotation', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: 'github:', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(() => parseLocationAnnotation(mockEntity)).toThrow( + expect.objectContaining({ + name: 'InputError', + message: `Failure to parse either protocol or location for entity: ${mockEntity.metadata.name}`, + }), + ); + }); + + it('should parse the location and protocol correctly for simple locations', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: 'file:./path', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(parseLocationAnnotation(mockEntity)).toEqual({ + protocol: 'file', + location: './path', + }); + }); + + it('should parse the location and protocol correctly for complex with unescaped locations', () => { + const mockEntity: TemplateEntityV1alpha1 = { + apiVersion: 'backstage.io/v1alpha1', + kind: 'Template', + metadata: { + annotations: { + [LOCATION_ANNOTATION]: 'github:https://lol.com/:something/shello', + }, + name: 'graphql-starter', + title: 'GraphQL Service', + description: + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, + }, + spec: { + type: 'cookiecutter', + path: './template', + }, + }; + + expect(parseLocationAnnotation(mockEntity)).toEqual({ + protocol: 'github', + location: 'https://lol.com/:something/shello', + }); + }); + }); +}); diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts index 0b1a72eaa3..4ae4f68164 100644 --- a/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/index.ts @@ -17,3 +17,4 @@ export * from './preparers'; export * from './types'; export * from './helpers'; export * from './file'; +export * from './github'; diff --git a/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts b/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts index 3251bd2780..a6e42c465f 100644 --- a/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts +++ b/plugins/scaffolder-backend/src/scaffolder/prepare/types.ts @@ -29,4 +29,4 @@ export type PreparerBuilder = { get(template: TemplateEntityV1alpha1): PreparerBase; }; -export type RemoteProtocol = 'file'; +export type RemoteProtocol = 'file' | 'github'; diff --git a/plugins/scaffolder-backend/src/service/router.ts b/plugins/scaffolder-backend/src/service/router.ts index 6636fc4b68..16b119da02 100644 --- a/plugins/scaffolder-backend/src/service/router.ts +++ b/plugins/scaffolder-backend/src/service/router.ts @@ -44,19 +44,21 @@ export async function createRouter( kind: 'Template', metadata: { annotations: { - 'backstage.io/managed-by-location': `file:${__dirname}/../../sample-templates/react-ssr-template/template.yaml`, + 'backstage.io/managed-by-location': + 'github:https://github.com/benjdlambert/backstage-graphql-template/blob/master/template.yaml', }, - name: 'react-ssr-template', - title: 'React SSR Template', + name: 'graphql-starter', + title: 'GraphQL Service', description: - 'Next.js application skeleton for creating isomorphic web applications.', - uid: '7357f4c5-aa58-4a1e-9670-18931eef771f', - etag: 'YWUxZWQyY2EtZDkxMC00MDM0LWI0ODAtMDgwMWY0YzdlMWIw', + 'A GraphQL starter template for backstage to get you up and running\nthe best pracices with GraphQL\n', + uid: '9cf16bad-16e0-4213-b314-c4eec773c50b', + etag: 'ZTkxMjUxMjUtYWY3Yi00MjU2LWFkYWMtZTZjNjU5ZjJhOWM2', + generation: 1, }, spec: { type: 'cookiecutter', - path: '.', + path: './template', }, }; diff --git a/plugins/techdocs/README.md b/plugins/techdocs/README.md index f25ffda3b2..10ddcf9411 100644 --- a/plugins/techdocs/README.md +++ b/plugins/techdocs/README.md @@ -4,6 +4,10 @@ Welcome to the TechDocs plugin - Spotify's docs-like-code approach built directl **WIP: This plugin is a work in progress. It is not ready for use yet. Follow our progress on [the Backstage Discord](https://discord.gg/MUpMjP2) under #docs-like-code or on [our GitHub Milestone](https://github.com/spotify/backstage/milestone/15).** +## Sections + +- [MkDocs](./mkdocs/README.md) + ## Getting started Your plugin has been added to the example app in this repository, meaning you'll be able to access it by running `yarn start` in the root directory, and then navigating to [/techdocs](http://localhost:3000/techdocs). diff --git a/plugins/techdocs/mkdocs/README.md b/plugins/techdocs/mkdocs/README.md new file mode 100644 index 0000000000..4d1c11d7b0 --- /dev/null +++ b/plugins/techdocs/mkdocs/README.md @@ -0,0 +1,13 @@ +# MkDocs + +Welcome to MkDocs. This is the TechDocs implementation of MkDocs. + +**WIP: This is a work in progress. It is not ready for use yet. Follow our progress on [the Backstage Discord](https://discord.gg/MUpMjP2) under #docs-like-code or on [our GitHub Milestone](https://github.com/spotify/backstage/milestone/15).** + +## Getting started + +``` + docker build ./container -t mkdocs-container + + docker run -w /content -v $(pwd)/mock-docs:/content -p 8000:8000 -it mkdocs-container serve -a 0.0.0.0:8000 +``` diff --git a/plugins/techdocs/mkdocs/container/Dockerfile b/plugins/techdocs/mkdocs/container/Dockerfile new file mode 100644 index 0000000000..1ae66589b6 --- /dev/null +++ b/plugins/techdocs/mkdocs/container/Dockerfile @@ -0,0 +1,25 @@ + +# Copyright 2020 Spotify AB +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +FROM python:3.7.7-alpine3.12 + +RUN apk update && apk --no-cache add gcc musl-dev +RUN pip install mkdocs==1.1.2 mkdocs-material==5.3.2 + +ADD ./techdocs-core /techdocs-core +RUN pip install --no-index /techdocs-core + +ENTRYPOINT [ "mkdocs" ] + diff --git a/plugins/techdocs/mkdocs/container/techdocs-core/requirements.txt b/plugins/techdocs/mkdocs/container/techdocs-core/requirements.txt new file mode 100644 index 0000000000..b3667f94ec --- /dev/null +++ b/plugins/techdocs/mkdocs/container/techdocs-core/requirements.txt @@ -0,0 +1 @@ +mkdocs==1.1.2 diff --git a/plugins/techdocs/mkdocs/container/techdocs-core/setup.py b/plugins/techdocs/mkdocs/container/techdocs-core/setup.py new file mode 100644 index 0000000000..faa8b8c46e --- /dev/null +++ b/plugins/techdocs/mkdocs/container/techdocs-core/setup.py @@ -0,0 +1,48 @@ +""" + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +""" +from setuptools import setup, find_packages + + +setup( + name='mkdocs-techdocs-core', + version='0.0.1', + description='A Mkdocs package that contains TechDocs defaults', + long_description='', + keywords='mkdocs', + url='https://github.com/spotify/backstage', + author='Spotify', + author_email='fossboard@spotify.com', + license='Apache-2.0', + python_requires='>=3.7', + install_requires=[ + 'mkdocs>=1.1.2' + ], + classifiers=[ + 'Development Status :: 1 - Planning', + 'Intended Audience :: Developers', + 'Intended Audience :: Information Technology', + 'License :: OSI Approved :: Apache Software License', + 'Programming Language :: Python', + 'Programming Language :: Python :: 3 :: Only', + 'Programming Language :: Python :: 3.7' + ], + packages=find_packages(), + entry_points={ + 'mkdocs.plugins': [ + 'techdocs-core = src.core:TechDocsCore' + ] + } +) diff --git a/plugins/techdocs/mkdocs/container/techdocs-core/src/__init__.py b/plugins/techdocs/mkdocs/container/techdocs-core/src/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/plugins/techdocs/mkdocs/container/techdocs-core/src/core.py b/plugins/techdocs/mkdocs/container/techdocs-core/src/core.py new file mode 100644 index 0000000000..e42a60d28b --- /dev/null +++ b/plugins/techdocs/mkdocs/container/techdocs-core/src/core.py @@ -0,0 +1,35 @@ +""" + * Copyright 2020 Spotify AB + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. +""" + +from mkdocs.plugins import BasePlugin, PluginCollection +from mkdocs.theme import Theme + +from mkdocs.contrib.search import SearchPlugin + +class TechDocsCore(BasePlugin): + def on_config(self, config): + # Theme + config['theme'] = Theme(name="material") + + # Plugins + del config['plugins']['techdocs-core'] + + search_plugin = SearchPlugin() + search_plugin.load_config({}) + config['plugins']['search'] = search_plugin + + return config + diff --git a/plugins/techdocs/mkdocs/mock-docs/.gitignore b/plugins/techdocs/mkdocs/mock-docs/.gitignore new file mode 100644 index 0000000000..45ddf0ae39 --- /dev/null +++ b/plugins/techdocs/mkdocs/mock-docs/.gitignore @@ -0,0 +1 @@ +site/ diff --git a/plugins/techdocs/mkdocs/mock-docs/docs/index.md b/plugins/techdocs/mkdocs/mock-docs/docs/index.md new file mode 100644 index 0000000000..bc437e6180 --- /dev/null +++ b/plugins/techdocs/mkdocs/mock-docs/docs/index.md @@ -0,0 +1 @@ +## hello mock docs diff --git a/plugins/techdocs/mkdocs/mock-docs/mkdocs.yml b/plugins/techdocs/mkdocs/mock-docs/mkdocs.yml new file mode 100644 index 0000000000..b14d82c4de --- /dev/null +++ b/plugins/techdocs/mkdocs/mock-docs/mkdocs.yml @@ -0,0 +1,8 @@ +site_name: 'mock-docs' + +nav: + - Home: index.md + +plugins: + - techdocs-core + diff --git a/yarn.lock b/yarn.lock index 88a9861af6..9bfd738603 100644 --- a/yarn.lock +++ b/yarn.lock @@ -3208,7 +3208,7 @@ dependencies: "@babel/types" "^7.4.4" -"@svgr/plugin-jsx@^4.3.3": +"@svgr/plugin-jsx@4.3.x", "@svgr/plugin-jsx@^4.3.3": version "4.3.3" resolved "https://registry.npmjs.org/@svgr/plugin-jsx/-/plugin-jsx-4.3.3.tgz#e2ba913dbdfbe85252a34db101abc7ebd50992fa" integrity sha512-cLOCSpNWQnDB1/v+SUENHH7a0XY09bfuMKdq9+gYvtuwzC2rU4I0wKGFEp1i24holdQdwodCtDQdFtJiTCWc+w== @@ -3218,7 +3218,7 @@ "@svgr/hast-util-to-babel-ast" "^4.3.2" svg-parser "^2.0.0" -"@svgr/plugin-svgo@^4.3.1": +"@svgr/plugin-svgo@4.3.x", "@svgr/plugin-svgo@^4.3.1": version "4.3.1" resolved "https://registry.npmjs.org/@svgr/plugin-svgo/-/plugin-svgo-4.3.1.tgz#daac0a3d872e3f55935c6588dd370336865e9e32" integrity sha512-PrMtEDUWjX3Ea65JsVCwTIXuSqa3CG9px+DluF1/eo9mlDrgrtFE7NE/DjdhjJgSM9wenlVBzkzneSIUgfUI/w== @@ -3227,7 +3227,21 @@ merge-deep "^3.0.2" svgo "^1.2.2" -"@svgr/webpack@^4.0.3": +"@svgr/rollup@4.3.x": + version "4.3.3" + resolved "https://registry.npmjs.org/@svgr/rollup/-/rollup-4.3.3.tgz#db8bc2746ae0930c14cba2409f417a6ac6aadb38" + integrity sha512-YwgnXN8xPRYFhkfoTUiZktjkjolthaK/lz0okzU09VcBvjx08R7yK1IEwXH3c98sMn8ORdNdiy4Qox78CMjljg== + dependencies: + "@babel/core" "^7.4.5" + "@babel/plugin-transform-react-constant-elements" "^7.0.0" + "@babel/preset-env" "^7.4.5" + "@babel/preset-react" "^7.0.0" + "@svgr/core" "^4.3.3" + "@svgr/plugin-jsx" "^4.3.3" + "@svgr/plugin-svgo" "^4.3.1" + rollup-pluginutils "^2.8.1" + +"@svgr/webpack@4.3.x", "@svgr/webpack@^4.0.3": version "4.3.3" resolved "https://registry.npmjs.org/@svgr/webpack/-/webpack-4.3.3.tgz#13cc2423bf3dff2d494f16b17eb7eacb86895017" integrity sha512-bjnWolZ6KVsHhgyCoYRFmbd26p8XVbulCzSG53BDQqAr+JOAderYK7CuYrB3bDjHJuF6LJ7Wrr42+goLRV9qIg== @@ -3580,6 +3594,11 @@ dependencies: "@types/node" "*" +"@types/git-url-parse@^9.0.0": + version "9.0.0" + resolved "https://registry.npmjs.org/@types/git-url-parse/-/git-url-parse-9.0.0.tgz#aac1315a44fa4ed5a52c3820f6c3c2fb79cbd12d" + integrity sha512-kA2RxBT/r/ZuDDKwMl+vFWn1Z0lfm1/Ik6Qb91wnSzyzCDa/fkM8gIOq6ruB7xfr37n6Mj5dyivileUVKsidlg== + "@types/glob@^7.1.1": version "7.1.1" resolved "https://registry.npmjs.org/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" @@ -3779,6 +3798,13 @@ resolved "https://registry.npmjs.org/@types/node/-/node-12.12.30.tgz#3501e6f09b954de9c404671cefdbcc5d9d7c45f6" integrity sha512-sz9MF/zk6qVr3pAnM0BSQvYIBK44tS75QC5N+VbWSE4DjCV/pJ+UzCW/F+vVnl7TkOPcuwQureKNtSSwjBTaMg== +"@types/nodegit@0.26.5": + version "0.26.5" + resolved "https://registry.npmjs.org/@types/nodegit/-/nodegit-0.26.5.tgz#f13032617da3894620b6132828f0136a65043e14" + integrity sha512-Dszf6yKBPLSPDC18QtY5LFRaRoE682/BHEhPQqwPtSBh0pG9uTfrhh1fnt61OSXiF8s4lBJunXbBpfwxvhQElQ== + dependencies: + "@types/node" "*" + "@types/normalize-package-data@^2.4.0": version "2.4.0" resolved "https://registry.npmjs.org/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e" @@ -4927,7 +4953,7 @@ arrify@^1.0.1: resolved "https://registry.npmjs.org/arrify/-/arrify-1.0.1.tgz#898508da2226f380df904728456849c1501a4b0d" integrity sha1-iYUI2iIm84DfkEcoRWhJwVAaSw0= -asap@^2.0.0: +asap@^2.0.0, asap@~2.0.3: version "2.0.6" resolved "https://registry.npmjs.org/asap/-/asap-2.0.6.tgz#e50347611d7e690943208bbdafebcbc2fb866d46" integrity sha1-5QNHYR1+aQlDIIu9r+vLwvuGbUY= @@ -5492,6 +5518,14 @@ bindings@^1.5.0: dependencies: file-uri-to-path "1.0.0" +bl@^1.0.0: + version "1.2.2" + resolved "https://registry.npmjs.org/bl/-/bl-1.2.2.tgz#a160911717103c07410cef63ef51b397c025af9c" + integrity sha512-e8tQYnZodmebYDWGH7KMRvtzKXaJHx3BbilrgZCfvyLUYdKpK1t5PSPmpkny/SgiTSCnjfLW7v5rlONXVFkQEA== + dependencies: + readable-stream "^2.3.5" + safe-buffer "^5.1.1" + bl@^4.0.1: version "4.0.2" resolved "https://registry.npmjs.org/bl/-/bl-4.0.2.tgz#52b71e9088515d0606d9dd9cc7aa48dc1f98e73a" @@ -5706,11 +5740,29 @@ btoa-lite@^1.0.0: resolved "https://registry.npmjs.org/btoa-lite/-/btoa-lite-1.0.0.tgz#337766da15801210fdd956c22e9c6891ab9d0337" integrity sha1-M3dm2hWAEhD92VbCLpxokaudAzc= +buffer-alloc-unsafe@^1.1.0: + version "1.1.0" + resolved "https://registry.npmjs.org/buffer-alloc-unsafe/-/buffer-alloc-unsafe-1.1.0.tgz#bd7dc26ae2972d0eda253be061dba992349c19f0" + integrity sha512-TEM2iMIEQdJ2yjPJoSIsldnleVaAk1oW3DBVUykyOLsEsFmEc9kn+SFFPz+gl54KQNxlDnAwCXosOS9Okx2xAg== + +buffer-alloc@^1.2.0: + version "1.2.0" + resolved "https://registry.npmjs.org/buffer-alloc/-/buffer-alloc-1.2.0.tgz#890dd90d923a873e08e10e5fd51a57e5b7cce0ec" + integrity sha512-CFsHQgjtW1UChdXgbyJGtnm+O/uLQeZdtbDo8mfUgYXCHSM1wgrVxXm6bSyrUuErEb+4sYVGCzASBRot7zyrow== + dependencies: + buffer-alloc-unsafe "^1.1.0" + buffer-fill "^1.0.0" + buffer-crc32@~0.2.3: version "0.2.13" resolved "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz#0d333e3f00eac50aa1454abd30ef8c2a5d9a7242" integrity sha1-DTM+PwDqxQqhRUq9MO+MKl2ackI= +buffer-fill@^1.0.0: + version "1.0.0" + resolved "https://registry.npmjs.org/buffer-fill/-/buffer-fill-1.0.0.tgz#f8f78b76789888ef39f205cd637f68e702122b2c" + integrity sha1-+PeLdniYiO858gXNY39o5wISKyw= + buffer-from@1.x, buffer-from@^1.0.0: version "1.1.1" resolved "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" @@ -6077,7 +6129,7 @@ chokidar@^3.2.2, chokidar@^3.3.0, chokidar@^3.3.1: optionalDependencies: fsevents "~2.1.2" -chownr@^1.1.1, chownr@^1.1.2: +chownr@^1.0.1, chownr@^1.1.1, chownr@^1.1.2: version "1.1.4" resolved "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz#6fc9d7b42d32a583596337666e7d08084da2cc6b" integrity sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg== @@ -9202,6 +9254,15 @@ fs-extra@^0.30.0: path-is-absolute "^1.0.0" rimraf "^2.2.8" +fs-extra@^7.0.0: + version "7.0.1" + resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" + integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== + dependencies: + graceful-fs "^4.1.2" + jsonfile "^4.0.0" + universalify "^0.1.0" + fs-extra@^9.0.0: version "9.0.0" resolved "https://registry.npmjs.org/fs-extra/-/fs-extra-9.0.0.tgz#b6afc31036e247b2466dc99c29ae797d5d4580a3" @@ -11862,6 +11923,13 @@ json5@^1.0.1: dependencies: minimist "^1.2.0" +json5@^2.1.0: + version "2.1.3" + resolved "https://registry.npmjs.org/json5/-/json5-2.1.3.tgz#c9b0f7fa9233bfe5807fe66fcf3a5617ed597d43" + integrity sha512-KXPvOm8K9IJKFM0bmdn8QXh7udDh1g/giieX0NLCaMnb4hEiVFqnop2ImTXCc5e0/oHz3LTqmHGtExn5hfMkOA== + dependencies: + minimist "^1.2.5" + jsonfile@^2.1.0: version "2.4.0" resolved "https://registry.npmjs.org/jsonfile/-/jsonfile-2.4.0.tgz#3736a2b428b87bbda0cc83b53fa3d633a35c2ae8" @@ -13245,6 +13313,11 @@ nan@^2.12.1: resolved "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz#7818f722027b2459a86f0295d434d1fc2336c52c" integrity sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg== +nan@^2.14.0: + version "2.14.1" + resolved "https://registry.npmjs.org/nan/-/nan-2.14.1.tgz#d7be34dfa3105b91494c3147089315eff8874b01" + integrity sha512-isWHgVjnFjh2x2yuJ/tj3JbwoHu3UC2dX5G/88Cm24yB6YopVgxvBObDY7n5xW6ExmFhJpSEQqFPvq9zaXc8Jw== + nano-css@^5.2.1: version "5.3.0" resolved "https://registry.npmjs.org/nano-css/-/nano-css-5.3.0.tgz#9d3cd29788d48b6a07f52aa4aec7cf4da427b6b5" @@ -13349,6 +13422,23 @@ node-forge@^0.7.0: resolved "https://registry.npmjs.org/node-forge/-/node-forge-0.7.6.tgz#fdf3b418aee1f94f0ef642cd63486c77ca9724ac" integrity sha512-sol30LUpz1jQFBjOKwbjxijiE3b6pjd74YwfD0fJOKPjF+fONKb2Yg8rYgS6+bK6VDl+/wfr4IYpC7jDzLUIfw== +node-gyp@^4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-4.0.0.tgz#972654af4e5dd0cd2a19081b4b46fe0442ba6f45" + integrity sha512-2XiryJ8sICNo6ej8d0idXDEMKfVfFK7kekGCtJAuelGsYHQxhj13KTf95swTCN2dZ/4lTfZ84Fu31jqJEEgjWA== + dependencies: + glob "^7.0.3" + graceful-fs "^4.1.2" + mkdirp "^0.5.0" + nopt "2 || 3" + npmlog "0 || 1 || 2 || 3 || 4" + osenv "0" + request "^2.87.0" + rimraf "2" + semver "~5.3.0" + tar "^4.4.8" + which "1" + node-gyp@^5.0.2: version "5.1.0" resolved "https://registry.npmjs.org/node-gyp/-/node-gyp-5.1.0.tgz#8e31260a7af4a2e2f994b0673d4e0b3866156332" @@ -13438,6 +13528,22 @@ node-pre-gyp@^0.11.0: semver "^5.3.0" tar "^4" +node-pre-gyp@^0.13.0: + version "0.13.0" + resolved "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.13.0.tgz#df9ab7b68dd6498137717838e4f92a33fc9daa42" + integrity sha512-Md1D3xnEne8b/HGVQkZZwV27WUi1ZRuZBij24TNaZwUPU3ZAFtvT6xxJGaUVillfmMKnn5oD1HoGsp2Ftik7SQ== + dependencies: + detect-libc "^1.0.2" + mkdirp "^0.5.1" + needle "^2.2.1" + nopt "^4.0.1" + npm-packlist "^1.1.6" + npmlog "^4.0.2" + rc "^1.2.7" + rimraf "^2.6.1" + semver "^5.3.0" + tar "^4" + node-releases@^1.1.29, node-releases@^1.1.52: version "1.1.52" resolved "https://registry.npmjs.org/node-releases/-/node-releases-1.1.52.tgz#bcffee3e0a758e92e44ecfaecd0a47554b0bcba9" @@ -13453,6 +13559,29 @@ node-request-interceptor@^0.2.5: debug "^4.1.1" headers-utils "^1.2.0" +nodegit-promise@~4.0.0: + version "4.0.0" + resolved "https://registry.npmjs.org/nodegit-promise/-/nodegit-promise-4.0.0.tgz#5722b184f2df7327161064a791d2e842c9167b34" + integrity sha1-VyKxhPLfcycWEGSnkdLoQskWezQ= + dependencies: + asap "~2.0.3" + +nodegit@0.26.5: + version "0.26.5" + resolved "https://registry.npmjs.org/nodegit/-/nodegit-0.26.5.tgz#1534d8aaa52de7acfbbe18de28df2075de86f7d2" + integrity sha512-l9l2zhcJ0V7FYzPdXIsuJcXN8UnLuhQgM+377HJfCYE/eupL/OWtMVvUOq42F9dRsgC3bAYH9j2Xbwr0lpYVZQ== + dependencies: + fs-extra "^7.0.0" + json5 "^2.1.0" + lodash "^4.17.14" + nan "^2.14.0" + node-gyp "^4.0.0" + node-pre-gyp "^0.13.0" + promisify-node "~0.3.0" + ramda "^0.25.0" + request-promise-native "^1.0.5" + tar-fs "^1.16.3" + nodemon@^2.0.2: version "2.0.4" resolved "https://registry.npmjs.org/nodemon/-/nodemon-2.0.4.tgz#55b09319eb488d6394aa9818148c0c2d1c04c416" @@ -13469,6 +13598,13 @@ nodemon@^2.0.2: undefsafe "^2.0.2" update-notifier "^4.0.0" +"nopt@2 || 3": + version "3.0.6" + resolved "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz#c6465dbf08abcd4db359317f79ac68a646b28ff9" + integrity sha1-xkZdvwirzU2zWTF/eaxopkayj/k= + dependencies: + abbrev "1" + nopt@^4.0.1: version "4.0.3" resolved "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz#a375cad9d02fd921278d954c2254d5aa57e15e48" @@ -13599,7 +13735,7 @@ npm-run-path@^4.0.0: dependencies: path-key "^3.0.0" -npmlog@^4.0.2, npmlog@^4.1.2: +"npmlog@0 || 1 || 2 || 3 || 4", npmlog@^4.0.2, npmlog@^4.1.2: version "4.1.2" resolved "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz#08a7f2a8bf734604779a9efa4ad5cc717abb954b" integrity sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg== @@ -13898,7 +14034,7 @@ os-tmpdir@^1.0.0, os-tmpdir@~1.0.2: resolved "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= -osenv@^0.1.4, osenv@^0.1.5: +osenv@0, osenv@^0.1.4, osenv@^0.1.5: version "0.1.5" resolved "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz#85cdfafaeb28e8677f416e287592b5f3f49ea410" integrity sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g== @@ -15093,6 +15229,13 @@ promise.series@^0.2.0: resolved "https://registry.npmjs.org/promise.series/-/promise.series-0.2.0.tgz#2cc7ebe959fc3a6619c04ab4dbdc9e452d864bbd" integrity sha1-LMfr6Vn8OmYZwEq029yeRS2GS70= +promisify-node@~0.3.0: + version "0.3.0" + resolved "https://registry.npmjs.org/promisify-node/-/promisify-node-0.3.0.tgz#b4b55acf90faa7d2b8b90ca396899086c03060cf" + integrity sha1-tLVaz5D6p9K4uQyjlomQhsAwYM8= + dependencies: + nodegit-promise "~4.0.0" + prompts@^2.0.1: version "2.3.2" resolved "https://registry.npmjs.org/prompts/-/prompts-2.3.2.tgz#480572d89ecf39566d2bd3fe2c9fccb7c4c0b068" @@ -15188,6 +15331,14 @@ public-encrypt@^4.0.0: randombytes "^2.0.1" safe-buffer "^5.1.2" +pump@^1.0.0: + version "1.0.3" + resolved "https://registry.npmjs.org/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" + integrity sha512-8k0JupWme55+9tCVE+FS5ULT3K6AbgqrGa58lTT49RpyfwwcGedHqaC5LlQNdEAumn/wFsu6aPwkuPMioy8kqw== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + pump@^2.0.0: version "2.0.1" resolved "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" @@ -15298,6 +15449,11 @@ ramda@^0.21.0: resolved "https://registry.npmjs.org/ramda/-/ramda-0.21.0.tgz#a001abedb3ff61077d4ff1d577d44de77e8d0a35" integrity sha1-oAGr7bP/YQd9T/HVd9RN536NCjU= +ramda@^0.25.0: + version "0.25.0" + resolved "https://registry.npmjs.org/ramda/-/ramda-0.25.0.tgz#8fdf68231cffa90bc2f9460390a0cb74a29b29a9" + integrity sha512-GXpfrYVPwx3K7RQ6aYT8KPS8XViSXUVJT1ONhoKPE9VAleW42YE+U+8VEyGWt41EnEQW7gwecYJriTI0pKoecQ== + randombytes@^2.0.0, randombytes@^2.0.1, randombytes@^2.0.5: version "2.1.0" resolved "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz#df6f84372f0270dc65cdf6291349ab7a473d4f2a" @@ -15903,7 +16059,7 @@ read@1, read@~1.0.1: dependencies: mute-stream "~0.0.4" -"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: +"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.0, readable-stream@^2.3.3, readable-stream@^2.3.5, readable-stream@^2.3.6, readable-stream@~2.3.6: version "2.3.7" resolved "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz#1eca1cf711aef814c04f62252a36a62f6cb23b57" integrity sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw== @@ -16381,6 +16537,13 @@ rifm@^0.7.0: dependencies: "@babel/runtime" "^7.3.1" +rimraf@2, rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: + version "2.7.1" + resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" + integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== + dependencies: + glob "^7.1.3" + rimraf@2.6.3: version "2.6.3" resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab" @@ -16388,13 +16551,6 @@ rimraf@2.6.3: dependencies: glob "^7.1.3" -rimraf@^2.2.8, rimraf@^2.5.4, rimraf@^2.6.1, rimraf@^2.6.2, rimraf@^2.6.3, rimraf@^2.7.1: - version "2.7.1" - resolved "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" - integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== - dependencies: - glob "^7.1.3" - rimraf@^3.0.0: version "3.0.2" resolved "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" @@ -16477,7 +16633,7 @@ rollup-pluginutils@2.4.1: estree-walker "^0.6.0" micromatch "^3.1.10" -rollup-pluginutils@2.8.2, rollup-pluginutils@^2.8.2: +rollup-pluginutils@2.8.2, rollup-pluginutils@^2.8.1, rollup-pluginutils@^2.8.2: version "2.8.2" resolved "https://registry.npmjs.org/rollup-pluginutils/-/rollup-pluginutils-2.8.2.tgz#72f2af0748b592364dbd3389e600e5a9444a351e" integrity sha512-EEp9NhnUkwY8aif6bxgovPHMoMoNr2FulJziTndpt5H9RdwC47GSGuII9XxpSdzVGM0GWrNPHV6ie1LTNJPaLQ== @@ -16695,6 +16851,11 @@ semver@^6.0.0, semver@^6.2.0, semver@^6.3.0: resolved "https://registry.npmjs.org/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== +semver@~5.3.0: + version "5.3.0" + resolved "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz#9b2ce5d3de02d17c6012ad326aa6b4d0cf54f94f" + integrity sha1-myzl094C0XxgEq0yaqa00M9U+U8= + send@0.17.1: version "0.17.1" resolved "https://registry.npmjs.org/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" @@ -17821,6 +17982,16 @@ tapable@^1.0.0, tapable@^1.1.3: resolved "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz#a1fccc06b58db61fd7a45da2da44f5f3a3e67ba2" integrity sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA== +tar-fs@^1.16.3: + version "1.16.3" + resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-1.16.3.tgz#966a628841da2c4010406a82167cbd5e0c72d509" + integrity sha512-NvCeXpYx7OsmOh8zIOP/ebG55zZmxLE0etfWRbWok+q2Qo8x/vOR/IJT1taADXPe+jsiu9axDb3X4B+iIgNlKw== + dependencies: + chownr "^1.0.1" + mkdirp "^0.5.1" + pump "^1.0.0" + tar-stream "^1.1.2" + tar-fs@~2.0.1: version "2.0.1" resolved "https://registry.npmjs.org/tar-fs/-/tar-fs-2.0.1.tgz#e44086c1c60d31a4f0cf893b1c4e155dabfae9e2" @@ -17831,6 +18002,19 @@ tar-fs@~2.0.1: pump "^3.0.0" tar-stream "^2.0.0" +tar-stream@^1.1.2: + version "1.6.2" + resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-1.6.2.tgz#8ea55dab37972253d9a9af90fdcd559ae435c555" + integrity sha512-rzS0heiNf8Xn7/mpdSVVSMAWAoy9bfb1WOTYC78Z0UQKeKa/CWS8FOq0lKGNa8DWKAn9gxjCvMLYc5PGXYlK2A== + dependencies: + bl "^1.0.0" + buffer-alloc "^1.2.0" + end-of-stream "^1.0.0" + fs-constants "^1.0.0" + readable-stream "^2.3.0" + to-buffer "^1.1.1" + xtend "^4.0.0" + tar-stream@^2.0.0: version "2.1.2" resolved "https://registry.npmjs.org/tar-stream/-/tar-stream-2.1.2.tgz#6d5ef1a7e5783a95ff70b69b97455a5968dc1325" @@ -18111,6 +18295,11 @@ to-arraybuffer@^1.0.0: resolved "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz#7d229b1fcc637e466ca081180836a7aabff83f43" integrity sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M= +to-buffer@^1.1.1: + version "1.1.1" + resolved "https://registry.npmjs.org/to-buffer/-/to-buffer-1.1.1.tgz#493bd48f62d7c43fcded313a03dcadb2e1213a80" + integrity sha512-lx9B5iv7msuFYE3dytT+KE5tap+rNYw+K4jVkb9R/asAb+pbBSM17jtunHplhBe6RRJdZx3Pn2Jph24O32mOVg== + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -19199,7 +19388,7 @@ which-pm-runs@^1.0.0: resolved "https://registry.npmjs.org/which-pm-runs/-/which-pm-runs-1.0.0.tgz#670b3afbc552e0b55df6b7780ca74615f23ad1cb" integrity sha1-Zws6+8VS4LVd9rd4DKdGFfI60cs= -which@^1.2.14, which@^1.2.9, which@^1.3.1: +which@1, which@^1.2.14, which@^1.2.9, which@^1.3.1: version "1.3.1" resolved "https://registry.npmjs.org/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==