├── .bazelversion ├── CODEOWNERS ├── .gitignore ├── tools └── bazel_stamp_vars.sh ├── .bzlgenrc ├── src ├── generators │ ├── types.ts │ ├── sass │ │ ├── sass.generator.flags.ts │ │ └── sass.generator.ts │ ├── index.ts │ ├── ng │ │ ├── ng.generator.flags.ts │ │ └── ng.generator.ts │ ├── ts │ │ ├── ts.generator.flags.ts │ │ └── ts.generator.ts │ ├── resolve-generator.ts │ ├── js │ │ └── nodejs-binary.generator.ts │ ├── builtin │ │ └── filegroup.generator.ts │ ├── bzl │ │ └── bzl-library.generator.ts │ ├── containers │ │ └── container-layer.generator.ts │ └── generator.ts ├── bzlgen.ts ├── logger.ts ├── BUILD ├── tracing.ts ├── main.ts ├── label.ts ├── rules.ts ├── buildozer.ts ├── flags.ts └── workspace.ts ├── tsconfig.json ├── .github └── workflows │ └── build.yml ├── test ├── flags.spec.ts ├── BUILD ├── rule.spec.ts ├── generators │ ├── bzl-library.generator.spec.ts │ ├── filegroup.generator.spec.ts │ ├── ng.generator.spec.ts │ ├── sass.generator.spec.ts │ └── ts.generator.spec.ts ├── buildozer.spec.ts ├── label.spec.ts └── workspace.spec.ts ├── .bazelrc ├── WORKSPACE ├── BUILD ├── LICENSE ├── package.json ├── index.bzl ├── CHANGELOG.md ├── README.md └── yarn.lock /.bazelversion: -------------------------------------------------------------------------------- 1 | 3.4.1 2 | -------------------------------------------------------------------------------- /CODEOWNERS: -------------------------------------------------------------------------------- 1 | * @mattem @JesseTatasciore -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules 2 | bazel-* 3 | .idea 4 | .ijwb 5 | .vscode 6 | yarn-error.log 7 | tools/bazel_version -------------------------------------------------------------------------------- /tools/bazel_stamp_vars.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | echo BUILD_SCM_VERSION $(git describe --abbrev=7 --tags HEAD) -------------------------------------------------------------------------------- /.bzlgenrc: -------------------------------------------------------------------------------- 1 | # sass generator flags 2 | --scss_library_suffix= 3 | 4 | # ng generator flags 5 | --ng_module_bundle_load=//tools/rules_bazel/defs.bzl 6 | 7 | # label mappings 8 | --label_mapping=rxjs/*=@npm//rxjs 9 | -------------------------------------------------------------------------------- /src/generators/types.ts: -------------------------------------------------------------------------------- 1 | export enum GeneratorType { 2 | NG = 'ng', 3 | NG_BUNDLE = 'ng_bundle', 4 | SASS = 'sass', 5 | TS = 'ts', 6 | JS_BINARY = 'js_binary', 7 | CONTAINER_LAYER = 'container_layer', 8 | FILEGROUP = 'filegroup' 9 | } 10 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "lib": [ 4 | "es2019" 5 | ], 6 | "moduleResolution": "node", 7 | "experimentalDecorators": true, 8 | "emitDecoratorMetadata": true, 9 | "esModuleInterop": true 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /src/bzlgen.ts: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env node 2 | 3 | import { run } from './main'; 4 | import { error, fatal } from './logger'; 5 | import { writeTracingProfile } from './tracing'; 6 | 7 | run() 8 | .catch(err => { 9 | error(err.message); 10 | error(err); 11 | writeTracingProfile(); 12 | 13 | fatal('Please report this error'); 14 | }); 15 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: CI 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | 8 | runs-on: [ubuntu-18.04] 9 | 10 | steps: 11 | - uses: actions/checkout@v1 12 | - name: fetch bazelisk 13 | run: | 14 | wget -O bazelisk https://github.com/bazelbuild/bazelisk/releases/download/v1.3.0/bazelisk-linux-amd64 15 | chmod +x ./bazelisk 16 | - name: test 17 | run: ./bazelisk test //... 18 | -------------------------------------------------------------------------------- /src/generators/sass/sass.generator.flags.ts: -------------------------------------------------------------------------------- 1 | import { Flag } from '../../flags'; 2 | 3 | export abstract class SassGeneratorFlags { 4 | @Flag({ 5 | description: 'Suffix used for scss_library rule names', 6 | type: 'string', 7 | default: 'scss_library' 8 | }) 9 | scss_library_suffix: string; 10 | 11 | @Flag({ 12 | description: 'Suffix used for scss_binary rule names', 13 | type: 'string', 14 | default: 'scss' 15 | }) 16 | scss_binary_suffix: string; 17 | } 18 | -------------------------------------------------------------------------------- /src/generators/index.ts: -------------------------------------------------------------------------------- 1 | // generators must be exported from here 2 | export * from './containers/container-layer.generator'; 3 | export * from './js/nodejs-binary.generator'; 4 | export * from './ng/ng.generator'; 5 | export * from './sass/sass.generator'; 6 | export * from './ts/ts.generator'; 7 | export * from './builtin/filegroup.generator'; 8 | export * from './bzl/bzl-library.generator'; 9 | 10 | export { GeneratorType } from './types'; 11 | export { getGenerator }from './resolve-generator'; 12 | -------------------------------------------------------------------------------- /src/generators/ng/ng.generator.flags.ts: -------------------------------------------------------------------------------- 1 | import { Flag } from '../../flags'; 2 | 3 | export abstract class NgGeneratorFlags { 4 | @Flag({ 5 | description: 'Generate sass_binary rules for .theme.scss files', 6 | type: 'boolean', 7 | default: true 8 | }) 9 | ng_generate_theme_binary: boolean; 10 | 11 | @Flag({ 12 | description: 'The package from which to load the macro for ng_module_bundle', 13 | type: 'string', 14 | requiresArg: true 15 | }) 16 | ng_module_bundle_load: string; 17 | } 18 | -------------------------------------------------------------------------------- /test/flags.spec.ts: -------------------------------------------------------------------------------- 1 | import { Flags, setupAndParseArgs } from '../src/flags'; 2 | 3 | describe('flags', () => { 4 | it('strips trailing path separator on path arg', () => { 5 | const args = ['ng', './bar/foo/']; 6 | const flags: Flags = setupAndParseArgs(args, true, 0); 7 | 8 | expect(flags.path).toBe('bar/foo'); 9 | }); 10 | 11 | it('leaves paths with no trailing separator intact', () => { 12 | const args = ['ng', './bar/foo']; 13 | const flags: Flags = setupAndParseArgs(args, true, 0); 14 | 15 | expect(flags.path).toBe('bar/foo'); 16 | }); 17 | }); 18 | -------------------------------------------------------------------------------- /.bazelrc: -------------------------------------------------------------------------------- 1 | build --strategy=TypeScriptCompile=worker 2 | test --test_output=errors 3 | 4 | build:release --stamp 5 | build:release --workspace_status_command=./tools/bazel_stamp_vars.sh 6 | 7 | # Use bazel run with `--config=debug` to turn on the NodeJS inspector agent. 8 | # The node process will break before user code starts and wait for the debugger to connect. 9 | test:debug --test_output=streamed --test_strategy=exclusive --test_timeout=9999 --nocache_test_results --define=VERBOSE_LOGS=1 10 | run:debug --define=VERBOSE_LOGS=1 -- --node_options=--inspect-brk 11 | build:debug --compilation_mode=dbg 12 | -------------------------------------------------------------------------------- /test/BUILD: -------------------------------------------------------------------------------- 1 | load("@npm//@bazel/typescript:index.bzl", "ts_library") 2 | load("@npm//@bazel/jasmine:index.bzl", "jasmine_node_test") 3 | 4 | ts_library( 5 | name = "test_srcs", 6 | testonly = 1, 7 | srcs = glob(["**/*.spec.ts"]), 8 | tsconfig = "//:tsconfig", 9 | deps = [ 10 | "//src", 11 | "@npm//@types/jasmine", 12 | "@npm//@types/node", 13 | "@npm//jasmine", 14 | "@npm//mock-fs", 15 | "@npm//@types/mock-fs", 16 | ], 17 | ) 18 | 19 | jasmine_node_test( 20 | name = "test", 21 | srcs = [":test_srcs"], 22 | data = [ 23 | "//src", 24 | "@npm//mock-fs", 25 | ], 26 | ) 27 | -------------------------------------------------------------------------------- /src/generators/ts/ts.generator.flags.ts: -------------------------------------------------------------------------------- 1 | import { Flag } from '../../flags'; 2 | 3 | export abstract class TsGeneratorFlags { 4 | @Flag({ 5 | description: 'The name of the npm bazel workspace', 6 | type: 'string', 7 | default: 'npm', 8 | requiresArg: true 9 | }) 10 | npm_workspace_name: string; 11 | 12 | @Flag({ 13 | description: 'The label used for any tsconfig attrs', 14 | type: 'string', 15 | requiresArg: true 16 | }) 17 | ts_config_label: string; 18 | 19 | @Flag({ 20 | description: 'Path to a tsconfig.json file that is used to attempt to resolve path mappings', 21 | type: 'string', 22 | requiresArg: true 23 | }) 24 | ts_config: string; 25 | } 26 | -------------------------------------------------------------------------------- /src/logger.ts: -------------------------------------------------------------------------------- 1 | import { Signale } from 'signale'; 2 | 3 | import { writeTracingProfile } from './tracing'; 4 | 5 | export const isDebugEnabled = process.argv.includes('--debug'); 6 | export const logger = new Signale({ stream: process.stderr }); 7 | 8 | export const lb = () => logger.log(''); 9 | 10 | export const log = logger.info; 11 | export const warn = logger.warn; 12 | export const error = logger.error; 13 | export const fatal = err => { 14 | error(err); 15 | if (isDebugEnabled) { writeTracingProfile(); } 16 | process.exit(1); 17 | }; 18 | export const debug = (...args) => { 19 | if (isDebugEnabled) { 20 | logger.debug.apply(logger, args); 21 | } 22 | }; 23 | 24 | export const out = line => process.stdout.write(line + '\n'); 25 | -------------------------------------------------------------------------------- /WORKSPACE: -------------------------------------------------------------------------------- 1 | workspace( 2 | name = "bzlgen", 3 | managed_directories = {"@npm": ["node_modules"]}, 4 | ) 5 | 6 | load("@bazel_tools//tools/build_defs/repo:http.bzl", "http_archive") 7 | 8 | http_archive( 9 | name = "build_bazel_rules_nodejs", 10 | sha256 = "6a67a8a1bf6fddc9113f73471029b819eef4575c3a936a4a01d57e411894d692", 11 | urls = ["https://github.com/bazelbuild/rules_nodejs/releases/download/2.0.2/rules_nodejs-2.0.2.tar.gz"], 12 | ) 13 | 14 | load("@build_bazel_rules_nodejs//:index.bzl", "node_repositories", "yarn_install") 15 | 16 | node_repositories( 17 | node_version = "12.13.0", 18 | package_json = ["//:package.json"], 19 | yarn_version = "1.19.1", 20 | ) 21 | 22 | yarn_install( 23 | name = "npm", 24 | package_json = "//:package.json", 25 | yarn_lock = "//:yarn.lock", 26 | ) 27 | -------------------------------------------------------------------------------- /BUILD: -------------------------------------------------------------------------------- 1 | load("@npm//@bazel/typescript:index.bzl", "ts_config") 2 | load("@build_bazel_rules_nodejs//:index.bzl", "pkg_npm") 3 | 4 | exports_files( 5 | [".bzlgenrc"], 6 | visibility = ["//:__subpackages__"], 7 | ) 8 | 9 | ts_config( 10 | name = "tsconfig", 11 | src = "tsconfig.json", 12 | visibility = ["//:__subpackages__"], 13 | deps = [], 14 | ) 15 | 16 | NPM_BUILD_FILE_CONTENT = """""" 17 | 18 | genrule( 19 | name = "gen_build", 20 | srcs = [], 21 | outs = ["_BUILD"], 22 | cmd = """echo '%s' >$@""" % NPM_BUILD_FILE_CONTENT, 23 | ) 24 | 25 | pkg_npm( 26 | name = "pkg", 27 | srcs = [ 28 | "package.json", 29 | ".bzlgenrc", 30 | "README.md", 31 | "LICENSE", 32 | "index.bzl", 33 | ], 34 | deps = [ 35 | "//src", 36 | ":gen_build", 37 | ], 38 | ) 39 | -------------------------------------------------------------------------------- /test/rule.spec.ts: -------------------------------------------------------------------------------- 1 | import { Label } from '../src/label'; 2 | import { Rule } from '../src/rules'; 3 | 4 | describe('rule', () => { 5 | it('can generate buildozer instance from a rule', () => { 6 | const label = Label.parseAbsolute('//foo:bar'); 7 | const tsLibraryRule = new Rule('ts_library', label) 8 | .setDeps(['baz']) 9 | .setSrcs(['foo.ts']) 10 | .setAttr('tsconfig', '//:tsconfig') 11 | .setVisibility(['//:__subpackages__']); 12 | 13 | const buildozer = tsLibraryRule.toCommands(); 14 | const commands = buildozer.toCommands().join('\n'); 15 | 16 | const expected = 17 | 'new_load @npm//@bazel/typescript:index.bzl ts_library|//foo:__pkg__\n' + 18 | 'new ts_library bar|//foo:__pkg__\n' + 19 | 'add deps baz|//foo:bar\n' + 20 | 'add srcs foo.ts|//foo:bar\n' + 21 | 'set tsconfig "//:tsconfig"|//foo:bar\n' + 22 | 'add visibility //:__subpackages__|//foo:bar'; 23 | 24 | expect(commands).toBe(expected); 25 | }); 26 | }); 27 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2020 Evertz Microsystems LTD 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 4 | 5 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 6 | 7 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /src/BUILD: -------------------------------------------------------------------------------- 1 | load("@npm//@bazel/typescript:index.bzl", "ts_library") 2 | load("@build_bazel_rules_nodejs//:index.bzl", "nodejs_binary") 3 | 4 | RUNTIME_NPM_DEPS = [ 5 | "@npm//@bazel/buildozer", 6 | "@npm//yargs", 7 | "@npm//signale", 8 | "@npm//lodash.kebabcase", 9 | "@npm//shelljs", 10 | "@npm//gonzales-pe", 11 | "@npm//@phenomnomnominal/tsquery", 12 | "@npm//typescript", 13 | "@npm//minimatch", 14 | "@npm//tsconfig-paths", 15 | "@npm//builtins", 16 | ] 17 | 18 | ts_library( 19 | name = "src", 20 | srcs = glob(["**/*.ts"]), 21 | tsconfig = "//:tsconfig", 22 | visibility = [ 23 | "//:__pkg__", 24 | "//test:__subpackages__", 25 | ], 26 | deps = [ 27 | "@npm//@types/node", 28 | "@npm//@types/shelljs", 29 | "@npm//@types/minimatch", 30 | ] + RUNTIME_NPM_DEPS, 31 | module_name = "@evertz/bzlgen/src", 32 | ) 33 | 34 | nodejs_binary( 35 | name = "bin", 36 | data = [ 37 | ":src", 38 | "//:.bzlgenrc", 39 | ] + RUNTIME_NPM_DEPS, 40 | entry_point = "//src:bzlgen.ts", 41 | tags = ["manual"], 42 | ) 43 | -------------------------------------------------------------------------------- /src/generators/resolve-generator.ts: -------------------------------------------------------------------------------- 1 | import { GeneratorType } from './types'; 2 | import { Workspace } from '../workspace'; 3 | import { BuildFileGenerator } from './generator'; 4 | import { fatal } from '../logger'; 5 | 6 | export const GENERATORS: Map> = new Map(); 7 | 8 | export function getGenerator(type: GeneratorType, workspace: Workspace): BuildFileGenerator { 9 | const ref = GENERATORS.get(type); 10 | 11 | if (!ref) { 12 | fatal(`No generator found for type ${type}`); 13 | } 14 | 15 | return new ref.generator(workspace); 16 | } 17 | 18 | export interface GeneratorOptions { 19 | type: string; 20 | 21 | description: string; 22 | 23 | flags?: any | any[]; 24 | 25 | deprecated?: boolean; 26 | 27 | implies?: { [k: string]: any }; 28 | } 29 | 30 | export interface Ref extends GeneratorOptions { 31 | generator: T; 32 | } 33 | 34 | export function Generator(options: GeneratorOptions) { 35 | return function (generator) { 36 | if (Array.isArray(options.type)) { 37 | options.type.forEach(type => { 38 | GENERATORS.set(type, { generator, ...options }); 39 | }); 40 | } else { 41 | GENERATORS.set(options.type, { generator, ...options }); 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /src/generators/js/nodejs-binary.generator.ts: -------------------------------------------------------------------------------- 1 | import { Label } from '../../label'; 2 | import { Rule } from '../../rules'; 3 | import { BuildFileGenerator } from '../generator'; 4 | import { Generator } from '../resolve-generator'; 5 | import { GeneratorType } from '../types'; 6 | 7 | class NodeJsBinaryRule extends Rule { 8 | constructor(label: Label) { 9 | super('nodejs_binary', label); 10 | } 11 | } 12 | 13 | @Generator({ 14 | type: GeneratorType.JS_BINARY, 15 | description: 'Generates a nodejs_binary rule setting the entry_point to the file at the given path' 16 | }) 17 | export class NodejsBinaryGenerator extends BuildFileGenerator { 18 | 19 | async generate(): Promise { 20 | const label = this.workspace.getLabelForPath().withTarget('bin'); 21 | const path = this.getFlags().path; 22 | 23 | const nodejsBinaryRule = new NodeJsBinaryRule(label) 24 | .setAttr('entry_point', this.workspace.getFileLabel(path).toString()) 25 | .setAttr('data', [this.workspace.getLabelForFile(path).toString()]); 26 | 27 | this.setDefaultVisibility(nodejsBinaryRule); 28 | this.buildozer.addRule(nodejsBinaryRule); 29 | } 30 | 31 | getGeneratorType(): GeneratorType { 32 | return GeneratorType.JS_BINARY; 33 | } 34 | 35 | supportsDirectories(): boolean { 36 | return false; 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /src/generators/builtin/filegroup.generator.ts: -------------------------------------------------------------------------------- 1 | import { Label } from '../../label'; 2 | import { Rule } from '../../rules'; 3 | import { BuildFileGenerator } from '../generator'; 4 | import { Generator } from '../resolve-generator'; 5 | import { GeneratorType } from '../types'; 6 | 7 | class FilegroupRule extends Rule { 8 | constructor(label: Label) { 9 | super('filegroup', label); 10 | } 11 | } 12 | 13 | @Generator({ 14 | type: GeneratorType.FILEGROUP, 15 | description: 'Generates a filegroup native rule containing all the files captured by the path parameter' 16 | }) 17 | export class FilegroupGenerator extends BuildFileGenerator { 18 | async generate(): Promise { 19 | const label = this.workspace.getLabelForPath(); 20 | 21 | const files = []; 22 | if (this.workspace.isDirectory()) { 23 | let labels = this.workspace.readDirectory() 24 | .map(file => this.workspace.getFileLabel(file)); 25 | 26 | files.push(...labels); 27 | } else { 28 | files.push(this.workspace.getFileLabel(this.getFlags().path)); 29 | } 30 | 31 | const filegroup = new FilegroupRule(label).setSrcs(files); 32 | this.setDefaultVisibility(filegroup); 33 | 34 | this.buildozer.addRule(filegroup); 35 | } 36 | 37 | getGeneratorType(): GeneratorType | string { 38 | return GeneratorType.FILEGROUP; 39 | } 40 | 41 | supportsDirectories(): boolean { 42 | return true; 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /test/generators/bzl-library.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import mockfs from 'mock-fs'; 2 | 3 | import { Workspace } from '../../src/workspace'; 4 | import { BzlLibraryGenerator } from '../../src/generators/bzl/bzl-library.generator'; 5 | import { setupAndParseArgs } from '../../src/flags'; 6 | 7 | describe('bzl_library generator', () => { 8 | let workspace: Workspace; 9 | let gen: BzlLibraryGenerator; 10 | 11 | afterEach(() => mockfs.restore()); 12 | 13 | it('can generate for files in a package', () => { 14 | const argv = [ 15 | 'bzl_library', 16 | './src', 17 | '--default_visibility=//:__subpackages__', 18 | '--base_dir=/home/workspace', 19 | '--no-assert_is_bazel_workspace' 20 | ]; 21 | 22 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 23 | gen = new BzlLibraryGenerator(workspace); 24 | 25 | mockfs({ 26 | '/home/workspace/src': { 27 | 'foo.bzl': '', 28 | 'bar.bzl': '', 29 | 'baz.txt': '' 30 | } 31 | }); 32 | 33 | gen.generate(); 34 | 35 | const commands = workspace.getBuildozer().toCommands().join('\n'); 36 | const expected = 37 | 'new_load @bazel_skylib//:bzl_library.bzl bzl_library|//src:__pkg__\n' + 38 | 'new bzl_library bzl|//src:__pkg__\n' + 39 | 'add srcs //src:bar.bzl //src:foo.bzl|//src:bzl\n' + 40 | 'add visibility //:__subpackages__|//src:bzl'; 41 | 42 | expect(commands).toEqual(expected); 43 | }); 44 | }); 45 | -------------------------------------------------------------------------------- /src/generators/bzl/bzl-library.generator.ts: -------------------------------------------------------------------------------- 1 | import { Label } from '../../label'; 2 | import { Rule } from '../../rules'; 3 | import { BuildFileGenerator } from '../generator'; 4 | import { Generator } from '../resolve-generator'; 5 | import { GeneratorType } from '../types'; 6 | 7 | class BzlLibraryRule extends Rule { 8 | constructor(label: Label) { 9 | super('bzl_library', label) 10 | } 11 | } 12 | 13 | @Generator({ 14 | type: 'bzl_library', 15 | description: 'Generates a bzl_library for a collection of bzl files' 16 | }) 17 | export class BzlLibraryGenerator extends BuildFileGenerator { 18 | async generate(): Promise { 19 | const label = this.workspace.getLabelForPath(); 20 | const bzl = label.withTarget('bzl'); 21 | 22 | const files = []; 23 | if (this.workspace.isDirectory()) { 24 | const labels = this.workspace.readDirectory() 25 | .filter(file => file.endsWith('.bzl')) 26 | .map(file => this.workspace.getFileLabel(file)); 27 | 28 | files.push(...labels); 29 | } else { 30 | files.push(this.workspace.getFileLabel(this.getFlags().path)); 31 | } 32 | 33 | const bzlLibraryRule = new BzlLibraryRule(bzl).setSrcs(files); 34 | this.setDefaultVisibility(bzlLibraryRule); 35 | 36 | this.buildozer.addRule(bzlLibraryRule); 37 | } 38 | 39 | getGeneratorType(): GeneratorType | string { 40 | return 'bzl_library'; 41 | } 42 | 43 | supportsDirectories(): boolean { 44 | return true; 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /src/generators/containers/container-layer.generator.ts: -------------------------------------------------------------------------------- 1 | import { Label } from '../../label'; 2 | import { Rule } from '../../rules'; 3 | import { BuildFileGenerator } from '../generator'; 4 | import { Generator } from '../resolve-generator'; 5 | import { GeneratorType } from '../types'; 6 | 7 | class ContainerLayerRule extends Rule { 8 | constructor(label: Label) { 9 | super('container_layer', label); 10 | } 11 | } 12 | 13 | @Generator({ 14 | type: GeneratorType.CONTAINER_LAYER, 15 | description: 'Generates a container_layer rule containing all the files captured by the path parameter' 16 | }) 17 | export class ContainerLayerGenerator extends BuildFileGenerator { 18 | 19 | async generate(): Promise { 20 | const label = this.workspace.getLabelForPath().withTarget('layer'); 21 | 22 | const files = []; 23 | if (this.workspace.isDirectory()) { 24 | let labels = this.workspace.readDirectory() 25 | .map(file => this.workspace.getFileLabel(file)); 26 | 27 | files.push(...labels); 28 | } else { 29 | files.push(this.workspace.getFileLabel(this.getFlags().path)); 30 | } 31 | 32 | const containerLayerRule = new ContainerLayerRule(label).setAttr('files', files); 33 | this.setDefaultVisibility(containerLayerRule); 34 | 35 | this.buildozer.addRule(containerLayerRule); 36 | } 37 | 38 | getGeneratorType(): GeneratorType { 39 | return GeneratorType.CONTAINER_LAYER; 40 | } 41 | 42 | supportsDirectories(): boolean { 43 | return true; 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@evertz/bzlgen", 3 | "version": "0.0.0-PLACEHOLDER", 4 | "author": { 5 | "email": "opensource@evertz.com", 6 | "name": "Evertz Devtools R&D", 7 | "url": "https://evertz.com" 8 | }, 9 | "keywords": [ 10 | "bazel", 11 | "generator", 12 | "buildozer", 13 | "build" 14 | ], 15 | "description": "Bazel Buildozer command file generator written in Typescript", 16 | "repository": { 17 | "type": "GIT", 18 | "url": "https://github.com/Evertz/bzlgen" 19 | }, 20 | "bugs": { 21 | "url": "https://github.com/Evertz/bzlgen/issues" 22 | }, 23 | "main": "src/index.js", 24 | "bin": { 25 | "bzlgen": "src/bzlgen.js" 26 | }, 27 | "dependencies": { 28 | "@bazel/buildozer": "3.4.0", 29 | "@phenomnomnominal/tsquery": "4.1.0", 30 | "builtins": "3.0.1", 31 | "gonzales-pe": "4.3.0", 32 | "lodash.kebabcase": "4.1.1", 33 | "minimatch": "3.0.4", 34 | "patch-package": "6.2.2", 35 | "shelljs": "0.8.4", 36 | "signale": "1.4.0", 37 | "tsconfig-paths": "3.9.0", 38 | "typescript": "3.8.3", 39 | "yargs": "15.4.1" 40 | }, 41 | "devDependencies": { 42 | "@bazel/jasmine": "2.0.2", 43 | "@bazel/typescript": "2.0.2", 44 | "@types/jasmine": "3.5.12", 45 | "@types/minimatch": "3.0.3", 46 | "@types/mock-fs": "4.10.0", 47 | "@types/node": "14.0.27", 48 | "@types/shelljs": "0.8.8", 49 | "@types/yargs": "15.0.9", 50 | "jasmine": "3.6.1", 51 | "mock-fs": "4.12.0" 52 | }, 53 | "license": "MIT" 54 | } 55 | -------------------------------------------------------------------------------- /src/tracing.ts: -------------------------------------------------------------------------------- 1 | import { writeFileSync } from 'fs'; 2 | import { tmpdir } from 'os'; 3 | import { join } from 'path'; 4 | 5 | /** 6 | * Utils to write a Chrome tracing profile 7 | * Adapted from https://github.com/bazelbuild/rules_typescript/blob/master/internal/tsc_wrapped/perf_trace.ts 8 | */ 9 | 10 | type Microseconds = number; 11 | 12 | function now(): Microseconds { 13 | const [sec, nsec] = process.hrtime(); 14 | return (sec * 1e6) + (nsec / 1e3); 15 | } 16 | 17 | // https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/edit 18 | interface Event { 19 | name: string; 20 | ph: 'B'|'E'|'X'|'C'|'O'; 21 | pid: number; 22 | tid: number; 23 | ts: Microseconds; 24 | dur?: Microseconds; 25 | args?: any; 26 | id?: string; 27 | } 28 | 29 | const events: Event[] = []; 30 | 31 | export const TRACER_PATH = join(tmpdir(), 'bzlgentracer.json'); 32 | 33 | export function wrap(name: string, f: () => T): T { 34 | const start = now(); 35 | try { 36 | return f(); 37 | } finally { 38 | const end = now(); 39 | events.push({name, ph: 'X', pid: 1, tid: 0, ts: start, dur: (end - start)}); 40 | } 41 | } 42 | 43 | export function counter(name: string, counts: {[name: string]: number}) { 44 | events.push({name, ph: 'C', pid: 1, tid: 0, ts: now(), args: counts}); 45 | } 46 | 47 | export function snapshot(name: string, obj: any) { 48 | events.push({name, id: '1', ph: 'O', pid: 1, tid: 0, ts: now(), args: { snapshot: obj }}); 49 | } 50 | 51 | export function writeTracingProfile() { 52 | try { 53 | writeFileSync(TRACER_PATH, JSON.stringify(events), { encoding: 'utf8' }); 54 | } catch (e) {} 55 | } 56 | -------------------------------------------------------------------------------- /test/buildozer.spec.ts: -------------------------------------------------------------------------------- 1 | import { Buildozer } from '../src/buildozer'; 2 | import { Label } from '../src/label'; 3 | 4 | describe('buildozer', () => { 5 | it('can merge default load sites with overrides', () => { 6 | const loads = new Map([['ts_library', '//tools/bazel/defaults.bzl']]); 7 | const buildozer = new Buildozer(loads); 8 | 9 | const sass = buildozer.getRuleLoadSite('sass_binary'); 10 | expect(sass).toEqual('@io_bazel_rules_sass//sass:sass.bzl'); 11 | 12 | const ts = buildozer.getRuleLoadSite('ts_library'); 13 | expect(ts).toEqual('//tools/bazel/defaults.bzl'); 14 | 15 | const unknown = buildozer.getRuleLoadSite('foo'); 16 | expect(unknown).toBeUndefined(); 17 | }); 18 | 19 | it('can add additional loads for rules not part of defaults', () => { 20 | const loads = new Map([['ev_pkg_node', '//ev/tooling/bazel:defs.bzl']]); 21 | const buildozer = new Buildozer(loads); 22 | 23 | const pkgNode = buildozer.getRuleLoadSite('ev_pkg_node'); 24 | expect(pkgNode).toEqual('//ev/tooling/bazel:defs.bzl'); 25 | }); 26 | 27 | it('can merge two buildozer instances', () => { 28 | const buildozer = new Buildozer(); 29 | const label = Label.parseAbsolute('//foo:bar'); 30 | buildozer.addSrc(['foo'], label); 31 | 32 | const buildozer2 = new Buildozer(); 33 | const label2 = Label.parseAbsolute('//:bin'); 34 | buildozer2.addAttr('entry_point', ['main.ts'], label2); 35 | 36 | buildozer.merge(buildozer2); 37 | const commands = buildozer.toCommands().join('\n'); 38 | 39 | const expected = `add srcs foo|//foo:bar\nadd entry_point main.ts|//:bin`; 40 | expect(expected).toEqual(commands); 41 | }); 42 | }); 43 | -------------------------------------------------------------------------------- /index.bzl: -------------------------------------------------------------------------------- 1 | load("@npm//@angular/bazel:index.bzl", _ng_module = "ng_module") 2 | load("@io_bazel_rules_sass//sass:sass.bzl", _sass_binary = "sass_binary", _sass_library = "sass_library") 3 | 4 | def ng_module( 5 | # name used for this rule 6 | name, 7 | # typescript sources 8 | srcs, 9 | # dependencies for the typescript files 10 | deps = [], 11 | # scss files used by the component 12 | style = None, 13 | # any dependencies needed for the scss style 14 | style_deps = [], 15 | # assets, eg html files etc 16 | assets = [], 17 | # theme file if required 18 | theme = None, 19 | # dependencies for the theme 20 | theme_deps = [], 21 | # the visibility of the ng_module 22 | visibility = ["//:__subpackages__"], 23 | **kwargs): 24 | if theme != None: 25 | _sass_binary( 26 | name = "%s_theme" % name, 27 | src = theme, 28 | deps = theme_deps, 29 | visibility = ["//:__subpackages__"], 30 | ) 31 | 32 | ng_module_assets = assets 33 | 34 | if style != None: 35 | _sass_binary( 36 | name = "%s_styles" % name, 37 | src = style, 38 | deps = style_deps, 39 | visibility = visibility, 40 | ) 41 | 42 | ng_module_assets = ng_module_assets + [":%s_styles" % name] 43 | 44 | _ng_module( 45 | name = name, 46 | srcs = srcs, 47 | assets = ng_module_assets, 48 | visibility = visibility, 49 | deps = [ 50 | "@npm//@angular/common", 51 | "@npm//@angular/core", 52 | "@npm//rxjs", 53 | ] + deps, 54 | **kwargs 55 | ) 56 | -------------------------------------------------------------------------------- /src/generators/generator.ts: -------------------------------------------------------------------------------- 1 | import { Flags } from '../flags'; 2 | import { Workspace } from '../workspace'; 3 | import { Buildozer } from '../buildozer'; 4 | import { GeneratorType } from './types'; 5 | import { Label } from '../label'; 6 | import { Rule } from '../rules'; 7 | 8 | export abstract class BuildFileGenerator { 9 | protected readonly buildozer: Buildozer; 10 | 11 | constructor(protected readonly workspace: Workspace) { 12 | this.buildozer = workspace.getBuildozer(); 13 | } 14 | 15 | /** 16 | * Run any validation rules here on the current flags or workspace 17 | * If an error is thrown then the message is printed to the user and the generator exits with code 1, 18 | * If false is returned then a generic error is shown and the process exits with code 1. 19 | */ 20 | public validate(): boolean { 21 | return true; 22 | } 23 | 24 | /** 25 | * Run the generator 26 | */ 27 | public abstract async generate(): Promise; 28 | 29 | /** 30 | * Get the type of generator this is 31 | */ 32 | public abstract getGeneratorType(): GeneratorType | string; 33 | 34 | /** 35 | * Return if this generator supports directories 36 | */ 37 | public abstract supportsDirectories(): boolean; 38 | 39 | /** 40 | * Returns the set of flags associated with this run 41 | */ 42 | protected getFlags(): Flags { 43 | return this.workspace.getFlags(); 44 | } 45 | 46 | /** 47 | * Sets the visibility of the rule at 'label' to the visibility set at the --default_visibility flag 48 | * @param label 49 | */ 50 | protected setDefaultVisibilityOn(label: Label) { 51 | if (this.getFlags().default_visibility) { 52 | this.buildozer.setVisibility([this.getFlags().default_visibility], label); 53 | } 54 | } 55 | 56 | protected setDefaultVisibility(rule: Rule) { 57 | if (this.getFlags().default_visibility) { 58 | rule.setVisibility([this.getFlags().default_visibility]); 59 | } 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | ## Changelog 2 | 3 | #### 0.0.0-PLACEHOLDER 4 | 5 | #### 0.5.1 6 | 7 | * **fix**: Remove @angular/core, @angular/common and rxjs dependencies when generating with the ng_bundle generator as these deps are already included by default 8 | * **fix**: Handle double quotes when resolving imports within Typescript files 9 | 10 | #### 0.5.0 11 | 12 | * **fix**: Don't evict unknown rule loads from load mappings 13 | * **refactor**: Split generator resolution and types into separate files [#40](https://github.com/Evertz/bzlgen/issues/40) 14 | * **feat**: Support generating `bzl_library` rules [#53](https://github.com/Evertz/bzlgen/pull/53) 15 | * **chore**: Updated npm dependencies 16 | * **chore**: Updated bazel dependencies [#55](https://github.com/Evertz/bzlgen/pull/55) 17 | 18 | #### 0.4.1 19 | 20 | * **fix**: Add `--pkg_default_dep_labels` defaulting to `true`. This causes generated dep labels to use the package default label (`//my/package`) 21 | rather than the file label of the imported dependency (`//my/package:foo`). bzlgen will generate targets with the package name when generating a directory [#20](https://github.com/Evertz/bzlgen/issues/20) 22 | 23 | #### 0.4.0 24 | 25 | * **feat**: Support generating `nodejs_binary` target. The `data` attr will be set to `entry_points` generating rule [#36](https://github.com/Evertz/bzlgen/pull/36) 26 | * **feat**: Use the buildozer API via the NodeJS bindings rather than invoking directly in a shell on a text file [#34](https://github.com/Evertz/bzlgen/pull/34) 27 | * **feat**: Support generating `ts_library` targets for a single file [#35](https://github.com/Evertz/bzlgen/pull/35) 28 | * **feat**: Support simple generation of `container_layer` targets, adding files at `path` to the `files` attribute [#38](https://github.com/Evertz/bzlgen/pull/38) 29 | * **feat**: Add `--pattern` flag. When `path` represents a directory, `pattern` is used as a glob for filtering files [#38](https://github.com/Evertz/bzlgen/pull/38) 30 | * **fix**: Handle NodeJS builtins, adding `@types/node` as a dep [#37](https://github.com/Evertz/bzlgen/pull/37) 31 | -------------------------------------------------------------------------------- /test/generators/filegroup.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import mockfs from 'mock-fs'; 2 | 3 | import { Workspace } from '../../src/workspace'; 4 | import { FilegroupGenerator } from '../../src/generators/builtin/filegroup.generator'; 5 | import { setupAndParseArgs } from '../../src/flags'; 6 | 7 | describe('filegroup generator', () => { 8 | let workspace: Workspace; 9 | let gen: FilegroupGenerator; 10 | 11 | afterEach(() => mockfs.restore()); 12 | 13 | it('can generate for files in a package', () => { 14 | const argv = [ 15 | 'filegroup', 16 | './src', 17 | '--default_visibility=//:__subpackages__', 18 | '--base_dir=/home/workspace', 19 | '--no-assert_is_bazel_workspace' 20 | ]; 21 | 22 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 23 | gen = new FilegroupGenerator(workspace); 24 | 25 | mockfs({ 26 | '/home/workspace/src': { 27 | 'foo.txt': '', 28 | 'bar.txt': '', 29 | 'baz.css': '' 30 | } 31 | }); 32 | 33 | gen.generate(); 34 | 35 | const commands = workspace.getBuildozer().toCommands().join('\n'); 36 | const expected = 37 | 'new filegroup src|//src:__pkg__\n' + 38 | 'add srcs //src:bar.txt //src:baz.css //src:foo.txt|//src:src\n' + 39 | 'add visibility //:__subpackages__|//src:src'; 40 | 41 | expect(commands).toEqual(expected); 42 | }); 43 | 44 | it('can generate for one file in a package', () => { 45 | const argv = [ 46 | 'filegroup', 47 | './src/foo.txt', 48 | '--base_dir=/home/workspace', 49 | '--no-assert_is_bazel_workspace' 50 | ]; 51 | 52 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 53 | gen = new FilegroupGenerator(workspace); 54 | 55 | mockfs({ 56 | '/home/workspace/src': { 57 | 'foo.txt': '', 58 | 'bar.txt': '', 59 | 'baz.css': '' 60 | } 61 | }); 62 | 63 | gen.generate(); 64 | 65 | const commands = workspace.getBuildozer().toCommands().join('\n'); 66 | const expected = 67 | 'new filegroup src|//src:__pkg__\n' + 68 | 'add srcs //src:foo.txt|//src:src'; 69 | 70 | expect(commands).toEqual(expected); 71 | }); 72 | 73 | }); 74 | -------------------------------------------------------------------------------- /src/main.ts: -------------------------------------------------------------------------------- 1 | import { inspect } from 'util'; 2 | 3 | import { setupAndParseArgs, Flags } from './flags'; 4 | import { debug, fatal, lb, log, warn } from './logger'; 5 | import { snapshot, wrap, TRACER_PATH } from './tracing'; 6 | import { Workspace } from './workspace'; 7 | import { getGenerator } from './generators'; 8 | 9 | function printFlags(flags: Flags) { 10 | log('Canonicalized Flags:'); 11 | log(`type=${inspect(flags.type)}`); 12 | log(`path=${inspect(flags.path)}`); 13 | 14 | Object.entries(flags).sort().forEach(value => { 15 | const flag = value[0]; 16 | if (flag === '_' || flag === '$0' || flag === 'path' || flag === 'type') { return; } 17 | const flagValue = value[1]; 18 | log(`\t--${flag}=${inspect(flagValue)}`); 19 | }); 20 | lb(); 21 | } 22 | 23 | export async function run() { 24 | const flags = setupAndParseArgs(process.argv, process.argv.includes('--no-rc')); 25 | 26 | if (flags.debug) { 27 | debug(`Writing tracer profile to '${TRACER_PATH}'`); 28 | } 29 | 30 | if (flags.canonicalize_flags || flags.debug) { 31 | printFlags(flags); 32 | snapshot('flags', flags); 33 | } 34 | 35 | log(`Generating ${flags.build_file_name} file with type '${flags.type}' for '${flags.path}'`); 36 | 37 | const workspace = new Workspace(flags); 38 | 39 | if (flags.assert_is_bazel_workspace) { 40 | wrap( 41 | 'testBaseDirSupportsBazel', 42 | () => workspace.testBaseDirSupportsBazel() 43 | ); 44 | } 45 | 46 | if (flags.nuke_build_file && workspace.hasBuildFileAtPath()) { 47 | warn('--nuke_build_file'); 48 | warn(`This will result in a loss of any manual edits to ${flags.build_file_name} file at ${workspace.getBuildFilePath()}`); 49 | } 50 | 51 | const generator = getGenerator(flags.type, workspace); 52 | 53 | if (workspace.isDirectory() && !generator.supportsDirectories()) { 54 | fatal(`${generator.getGeneratorType()} generator does not support generating for directory paths, please pass a single file`); 55 | } 56 | 57 | const isValid = generator.validate(); 58 | 59 | if (isValid) { 60 | await wrap('generate', async () => await generator.generate()); 61 | 62 | wrap('buildozer', () => workspace.invokeBuildozer()); 63 | 64 | // TODO(matt): we should know the labels that were generated, output them to stdout 65 | // so that we can do something like bazel build $(gen ng foo) 66 | // flags.output_bzl_labels 67 | } else { 68 | throw new Error('Invalid configuration or flags found'); 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /test/label.spec.ts: -------------------------------------------------------------------------------- 1 | import { Label } from '../src/label'; 2 | 3 | describe('labels', () => { 4 | it('can parse label with workspace, pkg and target', () => { 5 | const label = Label.parseAbsolute('@bzl//some/package/here:bin'); 6 | expect(label.getWorkspace()).toBe('bzl'); 7 | expect(label.getPackage()).toBe('some/package/here'); 8 | expect(label.getTarget()).toBe('bin'); 9 | }); 10 | 11 | it('can parse label with pkg and target', () => { 12 | const label = Label.parseAbsolute('//some/package/here:bin'); 13 | expect(label.getWorkspace()).toBe(''); 14 | expect(label.getPackage()).toBe('some/package/here'); 15 | expect(label.getTarget()).toBe('bin'); 16 | }); 17 | 18 | it('can parse label with workspace and target at root', () => { 19 | const label = Label.parseAbsolute('@foo//:bin'); 20 | expect(label.getWorkspace()).toBe('foo'); 21 | expect(label.getTarget()).toBe('bin'); 22 | }); 23 | 24 | it('can parse label with workspace and pkg', () => { 25 | const label = Label.parseAbsolute('@foo//bar'); 26 | expect(label.getWorkspace()).toBe('foo'); 27 | expect(label.getPackage()).toBe('bar'); 28 | expect(label.getTarget()).toBe('bar'); 29 | expect(label.toString()).toBe('@foo//bar:bar'); 30 | }); 31 | 32 | it('can parse label and return same string', () => { 33 | const label = Label.parseAbsolute('@bzl//some/package/here:bin'); 34 | expect(label.toString()).toBe('@bzl//some/package/here:bin'); 35 | }); 36 | 37 | it('can change target for label', () => { 38 | const label = Label.parseAbsolute('@bzl//some/package/here:bin'); 39 | expect(label.withTarget('foo').toString()).toBe('@bzl//some/package/here:foo'); 40 | }); 41 | 42 | it('can get default label', () => { 43 | const label = Label.parseAbsolute('@bzl//some/package/here:bin'); 44 | expect(label.asDefaultLabel().toString()).toBe('@bzl//some/package/here:here'); 45 | }); 46 | 47 | it('throws when parsing a non absolute label', () => { 48 | expect(() => Label.parseAbsolute(':bin')).toThrow(); 49 | }); 50 | 51 | it('can return the shortened label form', () => { 52 | Label.SHORTEN_LABELS = true; 53 | const label = Label.parseAbsolute('@bzl//some/package/here'); 54 | expect(label.toString()).toBe('@bzl//some/package/here'); 55 | 56 | const label2 = Label.parseAbsolute('@bzl//some/package/here:bin'); 57 | expect(label2.toString()).toBe('@bzl//some/package/here:bin'); 58 | 59 | Label.SHORTEN_LABELS = false; 60 | const label3 = Label.parseAbsolute('@bzl//some/package/here'); 61 | expect(label3.toString()).toBe('@bzl//some/package/here:here'); 62 | }); 63 | }); 64 | -------------------------------------------------------------------------------- /src/label.ts: -------------------------------------------------------------------------------- 1 | export class Label { 2 | static readonly WORKSPACE_MARKER = '@'; 3 | static readonly PKG_ROOT_MARKER = '//'; 4 | static readonly PKG_SEP = '/'; 5 | static readonly TARGET_ROOT_MARKER = ':'; 6 | 7 | static SHORTEN_LABELS = false; 8 | 9 | private constructor(private readonly workspace: string, 10 | private readonly pkg: string, 11 | private readonly target: string) {} 12 | 13 | static isAbsolute(label: string): boolean { 14 | if (!label) { return false; } 15 | return label.startsWith(Label.PKG_ROOT_MARKER) || label.startsWith(Label.WORKSPACE_MARKER); 16 | } 17 | 18 | static parseAbsolute(label: string): Label { 19 | if (!Label.isAbsolute(label)) { throw new Error(`Label '${label}' is not absolute`); } 20 | let workspace, pkg, target; 21 | 22 | const hasWorkspace = label.startsWith(Label.WORKSPACE_MARKER); 23 | const workspaceEnd = label.indexOf(Label.PKG_ROOT_MARKER); 24 | const pkgEnd = label.indexOf(Label.TARGET_ROOT_MARKER); 25 | 26 | if (hasWorkspace) { 27 | if (workspaceEnd < 0 && pkgEnd > -1) { 28 | // invalid label? 29 | throw new Error(`Label '${label}' is not valid`); 30 | } 31 | 32 | workspace = label.substring(Label.WORKSPACE_MARKER.length, workspaceEnd); 33 | } else { 34 | workspace = ''; 35 | } 36 | 37 | pkg = label.substring(workspaceEnd + Label.PKG_ROOT_MARKER.length, pkgEnd === -1 ? label.length : pkgEnd); 38 | target = pkgEnd === -1 ? pkg.split(Label.PKG_SEP).pop() : label.substring(pkgEnd + 1, label.length); 39 | 40 | return new Label(workspace, pkg, target); 41 | } 42 | 43 | getTarget(withMarker = false): string { 44 | return withMarker ? Label.TARGET_ROOT_MARKER + this.target : this.target; 45 | } 46 | 47 | getPackage(withMarker = false): string { 48 | return withMarker ? Label.PKG_ROOT_MARKER + this.pkg : this.pkg; 49 | } 50 | 51 | getWorkspace(withMarker = false): string { 52 | return this.workspace ? (withMarker ? Label.WORKSPACE_MARKER + this.workspace : this.workspace) : ''; 53 | } 54 | 55 | asDefaultLabel(): Label { 56 | return this.withTarget(this.getPackage().split(Label.PKG_SEP).pop()); 57 | } 58 | 59 | withTarget(target: string): Label { 60 | return Label.parseAbsolute( 61 | (this.workspace.length ? this.getWorkspace(true) : '') + 62 | this.getPackage(true) + 63 | Label.TARGET_ROOT_MARKER + target 64 | ); 65 | } 66 | 67 | toString() { 68 | const str = []; 69 | if (this.workspace.length) { 70 | str.push(this.getWorkspace(true)); 71 | } 72 | 73 | str.push(this.getPackage(true)); 74 | 75 | if (!this.pkg.endsWith(this.target) || !Label.SHORTEN_LABELS) { 76 | str.push(this.getTarget(true)); 77 | } 78 | 79 | return str.join(''); 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/rules.ts: -------------------------------------------------------------------------------- 1 | import { Buildozer, DEFAULT_LOAD_SITES } from './buildozer'; 2 | import { Label } from './label'; 3 | 4 | export type SingleAttrValue = string | Label; 5 | export type ArrayAttrValue = Array; 6 | export type AttrValue = SingleAttrValue | ArrayAttrValue; 7 | 8 | /** 9 | * Helper for creating new rule instances and transforming them into a Buildozer instance 10 | */ 11 | export class Rule { 12 | protected attrs = new Map(); 13 | protected pAttrs = new Map(); 14 | 15 | protected readonly location: Label; 16 | 17 | static fromKindAndName(kind: string, pathTo: string, name: string, load?: string): Rule { 18 | return new Rule( 19 | kind, 20 | Label.parseAbsolute(`//${pathTo}:${name}`), 21 | load ?? DEFAULT_LOAD_SITES.get(kind) 22 | ); 23 | } 24 | 25 | constructor(public readonly kind: string, 26 | public readonly label: Label, 27 | public readonly load?: string) { 28 | this.location = this.label.withTarget('__pkg__'); 29 | } 30 | 31 | setAttr(name: string, value: AttrValue): this { 32 | if (!value || Array.isArray(value) && value.length === 0) { return this; } 33 | 34 | this.attrs.set(name, value); 35 | return this; 36 | } 37 | 38 | getAttr(name: string): AttrValue { 39 | return this.attrs.get(name); 40 | } 41 | 42 | setVisibility(visibility: ArrayAttrValue): this { 43 | this.setAttr('visibility', visibility); 44 | return this; 45 | } 46 | 47 | setSrcs(value: ArrayAttrValue): this { 48 | this.setAttr('srcs', value); 49 | return this; 50 | } 51 | 52 | setSrc(value: SingleAttrValue): this { 53 | this.setAttr('src', value); 54 | return this; 55 | } 56 | 57 | setDeps(value: ArrayAttrValue): this { 58 | this.setAttr('deps', value); 59 | return this; 60 | } 61 | 62 | setData(value: ArrayAttrValue): this { 63 | this.setAttr('data', value); 64 | return this; 65 | } 66 | 67 | setTags(value: string[]): this { 68 | this.setAttr('tags', value); 69 | return this; 70 | } 71 | 72 | getVisibility(): SingleAttrValue { 73 | return this.attrs.get('visibility') as SingleAttrValue; 74 | } 75 | 76 | setPrivateAttr(name: string, value: AttrValue): this { 77 | this.pAttrs.set(name, value); 78 | return this; 79 | } 80 | 81 | getPrivateAttr(name: string): AttrValue { 82 | return this.pAttrs.get(name); 83 | } 84 | 85 | toCommands(buildozer: Buildozer = new Buildozer()): Buildozer { 86 | if (this.load) { 87 | buildozer.newLoad(this.load, this.kind, this.location); 88 | } else { 89 | buildozer.loadRule(this.kind, this.location); 90 | } 91 | 92 | buildozer.newRule(this.kind, this.label); 93 | 94 | this.attrs.forEach((value, attr) => { 95 | if (Array.isArray(value)) { 96 | buildozer.addAttr(attr, value, this.label); 97 | } else { 98 | buildozer.setAttr(attr, value, this.label); 99 | } 100 | }); 101 | 102 | return buildozer; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Bazel BUILD file generator 2 | 3 | Tool to generate [Bazel](https://bazel.build) build files for a number of different rule sets and languages. Generation is done via [buildozer](https://github.com/bazelbuild/buildtools/tree/master/buildozer) commands for a given rule and source file or directory. 4 | 5 | The generator can create rules for the following and can be extended to provide more 6 | 7 | * sass_library 8 | * sass_binary 9 | * ng_module 10 | * ts_library 11 | * nodejs_binary 12 | * container_layer 13 | * filegroup 14 | * bzl_library 15 | 16 | The generator is _somewhat_ flexible in the source structure, but does make a number of assumptions in certain cases. 17 | It will try and 'best guess' labels from other packages. It's currently not expected to generate a 100% correct and working build file, 18 | but will (in most cases) generate a ~80-90% best effort and reduce the boilerplate needed. 19 | 20 | #### Running the generator 21 | bzlgen can be installed from npm 22 | ``` 23 | npm i -g @evertz/bzlgen 24 | ``` 25 | 26 | Then run the generator, passing the type to generate and the path or file to generate for (not all generators support single files or directories) 27 | 28 | ``` 29 | bzlgen ng ./home 30 | ``` 31 | 32 | There are many option other flags that can be set to customize the output of the generator, see `--help` for more 33 | 34 | The generator can also be run from source if needed: 35 | ``` 36 | bazel run //src:bin -- --help 37 | ``` 38 | 39 | ### Mapping rules to load statements 40 | By default, the generator will load rules from the workspace. However this can be changed by setting `load_mapping` flags 41 | This tells the generator where to load a given rule from. 42 | 43 | This will load `sass_library` from `//tools/defaults.bzl`. This allows those with marcos overriding rule definitions to specify 44 | the correct load site 45 | ``` 46 | --load_mapping=sass_library=//tools/defaults.bzl 47 | ``` 48 | 49 | ### Mapping sources to labels 50 | Label mappings can be added to either override or augment the 51 | mapping between a source file and its label. Labels mappings are always the relative path from the root of the workspace 52 | (or in the case of node_modules, simply the module name) 53 | 54 | ``` 55 | --label_mapping path/to/src/component.ts=//some/other:label 56 | ``` 57 | 58 | Mappings can also contain glob patterns, allowing many paths or subpaths to be mapped to a specific label. 59 | The example below will map all files in the `path/to` subdirectory to the label `//:foo` 60 | 61 | ``` 62 | --label_mapping path/to/**/*=//:foo 63 | ``` 64 | 65 | Imports can be ignored by setting the path to a blank label 66 | 67 | #### Bazel Query 68 | 69 | The generator has experimental use of `bazel query` to attempt to resolve source files to labels. This can be useful if 70 | BUILD files have already been generated in the repo. 71 | Mappings added via the `--label_mapping` flag will have priority over any query results or best guess label generation. 72 | 73 | The `--use_bazel_query` can be set to opt-in to this behaviour 74 | 75 | ### .bzlgenrc 76 | As bzlgen has a large number of flags, it can read them from a `.bzlgenrc` file in the root of the repo when to command is run. 77 | 78 | Each line should contain one flag, all lines are processed, except those starting with `#` 79 | ``` 80 | # load mappings 81 | --load_mapping=sass_library=//tools/defaults.bzl 82 | --load_mapping=sass_binary=//tools/defaults.bzl 83 | 84 | # label mappings 85 | --label_mapping=rxjs/operators=@npm//rxjs 86 | ``` 87 | -------------------------------------------------------------------------------- /src/generators/sass/sass.generator.ts: -------------------------------------------------------------------------------- 1 | import * as gonzales from 'gonzales-pe'; 2 | import { ParsedPath } from 'path'; 3 | 4 | import { Flags } from '../../flags'; 5 | import { Label } from '../../label'; 6 | import { log } from '../../logger'; 7 | import { Rule } from '../../rules'; 8 | import { Workspace } from '../../workspace'; 9 | import { BuildFileGenerator } from '../generator'; 10 | import { Generator } from '../resolve-generator'; 11 | import { GeneratorType } from '../types'; 12 | import { SassGeneratorFlags } from './sass.generator.flags'; 13 | 14 | export class SassBinaryRule extends Rule { 15 | constructor(label: Label) { 16 | super('sass_binary', label); 17 | } 18 | } 19 | 20 | export class SassLibraryRule extends Rule { 21 | constructor(label: Label) { 22 | super('sass_library', label); 23 | } 24 | } 25 | 26 | @Generator({ 27 | type: GeneratorType.SASS, 28 | flags: SassGeneratorFlags, 29 | description: 'Generates a sass_binary or sass_library depending on the input path type' 30 | }) 31 | export class SassGenerator extends BuildFileGenerator { 32 | private readonly flags: Flags; 33 | 34 | constructor(workspace: Workspace) { 35 | super(workspace); 36 | 37 | this.flags = this.getFlags(); 38 | } 39 | 40 | async generate(): Promise { 41 | const scss = this.workspace.readFileAtPath(); 42 | 43 | const deps = this.calculateDeps(scss); 44 | 45 | const scssFileInfo = this.workspace.getPathInfo(); 46 | const isSassLib = this.isSassLib(scssFileInfo); 47 | 48 | const ruleName = this.calculateRuleName(scssFileInfo.base, 49 | this.flags.scss_library_suffix, this.flags.scss_binary_suffix, isSassLib); 50 | 51 | const label = this.workspace.getLabelForPath(); 52 | 53 | let rule: Rule; 54 | 55 | if (isSassLib) { 56 | rule = new SassLibraryRule(label.withTarget(ruleName)) 57 | .setSrcs([scssFileInfo.base]) 58 | .setDeps(deps); 59 | } else { 60 | rule = new SassBinaryRule(label.withTarget(ruleName)) 61 | .setSrc(scssFileInfo.base) 62 | .setDeps(deps); 63 | } 64 | 65 | this.setDefaultVisibility(rule); 66 | this.buildozer.addRule(rule); 67 | } 68 | 69 | getGeneratorType(): GeneratorType { 70 | return GeneratorType.SASS; 71 | } 72 | 73 | supportsDirectories(): boolean { 74 | return false; 75 | } 76 | 77 | isSassLib(fileInfo: ParsedPath): boolean { 78 | return fileInfo.name.startsWith('_'); 79 | } 80 | 81 | calculateRuleName(fileName: string, librarySuffix: string, binarySuffix: string, isSassLib: boolean): string { 82 | return this.workspace 83 | .getLabelForFile(fileName, isSassLib ? librarySuffix : binarySuffix) 84 | .getTarget(); 85 | } 86 | 87 | calculateDeps(scss: string, resultsAreLabels = true): string[] { 88 | const flags = this.workspace.getFlags(); 89 | const parseTree = gonzales.parse(scss, { syntax: 'scss' }); 90 | 91 | const deps = new Set(); 92 | 93 | parseTree.forEach('atrule', node => { 94 | const isAtImportAtRule = node.content.find(content => { 95 | if (content.type !== 'atkeyword') { return false; } 96 | return content.content.find(n => n.type === 'ident' && n.content === 'import'); 97 | }); 98 | 99 | if (!isAtImportAtRule) { return; } 100 | 101 | const atImportPathNode = node.content.find(n => n.type === 'string'); 102 | const importPath = atImportPathNode.content 103 | .replace(/'/g, '') 104 | .replace(/"/g, ''); 105 | 106 | if (resultsAreLabels) { 107 | const label = this.calculateDependencyLabel(importPath, this.flags.scss_library_suffix); 108 | 109 | if (flags.verbose_import_mappings) { 110 | log(`${importPath}=${label}`); 111 | } 112 | 113 | deps.add(label); 114 | } else { 115 | deps.add(importPath); 116 | } 117 | }); 118 | 119 | return Array.from(deps); 120 | } 121 | 122 | calculateDependencyLabel(importPath: string, librarySuffix: string): string { 123 | return this.workspace.getLabelForFile(importPath, librarySuffix).toString(); 124 | } 125 | } 126 | -------------------------------------------------------------------------------- /test/generators/ng.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import mockfs from 'mock-fs'; 2 | 3 | import { setupAndParseArgs } from '../../src/flags'; 4 | import { NgGenerator } from '../../src/generators/ng/ng.generator'; 5 | import { Workspace } from '../../src/workspace'; 6 | import { GeneratorType } from '../../src/generators/types'; 7 | 8 | describe('ng generator', () => { 9 | const NG_COMPONENT = 10 | `import { component } from '@angular/core'; 11 | import * as r from 'rxjs/operators'; 12 | import { Observable } from 'rxjs'; 13 | @Component({ 14 | templateUrl: './component.component.html', 15 | styleUrls: ['./component.component.scss'] 16 | }) 17 | export class SomeComponent {} 18 | `; 19 | 20 | const NG_MODULE = 21 | `import { NgModule } from '@angular/core'; 22 | import { SomeComponent } from './component.component'; 23 | `; 24 | 25 | const setupForParse = type => { 26 | const argv = [ 27 | type, 28 | './src/component', 29 | '--base_dir=/home/workspace', 30 | '--no-assert_is_bazel_workspace', 31 | '--load_mapping=sass_library=@io_bazel_rules_sass//sass:sass.bzl', 32 | '--load_mapping=sass_binary=@io_bazel_rules_sass//sass:sass.bzl', 33 | '--load_mapping=ng_module=@npm_angular_bazel//:index.bzl', 34 | '--label_mapping=rxjs/operators=@npm//rxjs', 35 | '--ng_module_bundle_load=//tools/rules_bazel/defs.bzl', 36 | '--ng_generate_theme_binary' 37 | ]; 38 | return new Workspace(setupAndParseArgs(argv, true, 0)); 39 | }; 40 | 41 | const setupMockFs = () => { 42 | mockfs({ 43 | '/home/workspace/src/component': { 44 | 'component.component.ts': NG_COMPONENT, 45 | 'component.module.ts': NG_MODULE, 46 | 'component.component.scss': '', 47 | 'component.component.html': '', 48 | 'component.theme.scss': '' 49 | } 50 | }); 51 | }; 52 | 53 | afterEach(() => mockfs.restore()); 54 | 55 | it('can generate ng_module with style and theme', () => { 56 | const workspace = setupForParse(GeneratorType.NG); 57 | const gen = new NgGenerator(workspace); 58 | 59 | setupMockFs(); 60 | 61 | gen.generate(); 62 | 63 | const commands = workspace.getBuildozer().toCommands(); 64 | 65 | const expected = 66 | 'new_load @npm_angular_bazel//:index.bzl ng_module|//src/component:__pkg__\n' + 67 | 'new ng_module component|//src/component:__pkg__\n' + 68 | 'new_load @io_bazel_rules_sass//sass:sass.bzl sass_binary|//src/component:__pkg__\n' + 69 | 'new sass_binary component-component-styles|//src/component:__pkg__\n' + 70 | 'new_load @io_bazel_rules_sass//sass:sass.bzl sass_binary|//src/component:__pkg__\n' + 71 | 'new sass_binary component-theme-theme|//src/component:__pkg__\n' + 72 | 'add srcs component.component.ts component.module.ts|//src/component:component\n' + 73 | 'add deps @npm//@angular/core:core @npm//rxjs:rxjs|//src/component:component\n' + 74 | 'add assets component.component.html //src/component:component-component-styles|//src/component:component\n' + 75 | 'set src "component.component.scss"|//src/component:component-component-styles\n' + 76 | 'set src "component.theme.scss"|//src/component:component-theme-theme'; 77 | 78 | expect(commands.join('\n')).toEqual(expected); 79 | }); 80 | 81 | it('can generate ng_module bundles with style and theme', () => { 82 | const workspace = setupForParse(GeneratorType.NG_BUNDLE); 83 | const gen = new NgGenerator(workspace); 84 | 85 | setupMockFs(); 86 | 87 | gen.generate(); 88 | 89 | const commands = workspace.getBuildozer().toCommands(); 90 | const expected = 91 | 'new_load //tools/rules_bazel/defs.bzl ng_module|//src/component:__pkg__\n' + 92 | 'new ng_module component|//src/component:__pkg__\n' + 93 | 'add srcs component.component.ts component.module.ts|//src/component:component\n' + 94 | 'set style "component.component.scss"|//src/component:component\n' + 95 | 'add assets component.component.html|//src/component:component\n' + 96 | 'set theme "component.theme.scss"|//src/component:component'; 97 | 98 | expect(commands.join('\n')).toEqual(expected); 99 | }); 100 | }); 101 | -------------------------------------------------------------------------------- /test/generators/sass.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import mockfs from 'mock-fs'; 2 | 3 | import { setupAndParseArgs } from '../../src/flags'; 4 | import { SassGenerator } from '../../src/generators/sass/sass.generator'; 5 | import { Workspace } from '../../src/workspace'; 6 | 7 | describe('sass generator', () => { 8 | let workspace: Workspace; 9 | let gen: SassGenerator; 10 | 11 | afterEach(() => mockfs.restore()); 12 | 13 | describe('sass_library', () => { 14 | it('can generate a sass_library with no deps', () => { 15 | const argv = [ 16 | 'sass', 17 | './src/component/_foo.scss', 18 | '--base_dir=/home/workspace', 19 | '--no-assert_is_bazel_workspace', 20 | '--load_mapping=sass_library=@io_bazel_rules_sass//sass:sass.bzl' 21 | ]; 22 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 23 | gen = new SassGenerator(workspace); 24 | 25 | mockfs({ '/home/workspace/src': { component: { '_foo.scss': '' } } }); 26 | 27 | // trigger the generator 28 | gen.generate(); 29 | 30 | // assert the buildozer commands are correct 31 | const commands = workspace.getBuildozer().toCommands().join('\n'); 32 | const expected = 33 | 'new_load @io_bazel_rules_sass//sass:sass.bzl sass_library|//src/component:__pkg__\n' + 34 | 'new sass_library foo-scss_library|//src/component:__pkg__\n' + 35 | 'add srcs _foo.scss|//src/component:foo-scss_library'; 36 | 37 | expect(commands).toEqual(expected); 38 | }); 39 | 40 | it('can generate a sass_library with deps', () => { 41 | const argv = [ 42 | 'sass', 43 | './src/component/_bar.scss', 44 | '--base_dir=/home/workspace', 45 | '--no-assert_is_bazel_workspace', 46 | '--load_mapping=sass_library=@io_bazel_rules_sass//sass:sass.bzl' 47 | ]; 48 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 49 | gen = new SassGenerator(workspace); 50 | 51 | mockfs({ 52 | '/home/workspace/src': { 53 | component: { '_foo.scss': '', '_bar.scss': '@import "./foo";' } 54 | } 55 | }); 56 | 57 | // trigger the generator 58 | gen.generate(); 59 | 60 | // assert the buildozer commands are correct 61 | const commands = workspace.getBuildozer().toCommands().join('\n'); 62 | const expected = 63 | 'new_load @io_bazel_rules_sass//sass:sass.bzl sass_library|//src/component:__pkg__\n' + 64 | 'new sass_library bar-scss_library|//src/component:__pkg__\n' + 65 | 'add srcs _bar.scss|//src/component:bar-scss_library\n' + 66 | 'add deps //src/component:foo-scss_library|//src/component:bar-scss_library'; 67 | 68 | expect(commands).toEqual(expected); 69 | }); 70 | }); 71 | 72 | describe('sass_binary', () => { 73 | it('can generate a sass_binary with no deps', () => { 74 | const argv = [ 75 | 'sass', 76 | './src/component/foo.scss', 77 | '--base_dir=/home/workspace', 78 | '--no-assert_is_bazel_workspace', 79 | '--scss_binary_suffix=css', 80 | '--load_mapping=sass_binary=@io_bazel_rules_sass//sass:sass.bzl' 81 | ]; 82 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 83 | gen = new SassGenerator(workspace); 84 | 85 | mockfs({ '/home/workspace/src': { component: { 'foo.scss': '' } } }); 86 | 87 | // trigger the generator 88 | gen.generate(); 89 | 90 | // assert the buildozer commands are correct 91 | const commands = workspace.getBuildozer().toCommands().join('\n'); 92 | const expected = 93 | 'new_load @io_bazel_rules_sass//sass:sass.bzl sass_binary|//src/component:__pkg__\n' + 94 | 'new sass_binary foo-css|//src/component:__pkg__\n' + 95 | 'set src "foo.scss"|//src/component:foo-css'; 96 | 97 | expect(commands).toEqual(expected); 98 | }); 99 | 100 | it('can generate a sass_binary with deps', () => { 101 | const argv = [ 102 | 'sass', 103 | './src/component/foo.scss', 104 | '--base_dir=/home/workspace', 105 | '--no-assert_is_bazel_workspace', 106 | '--load_mapping=sass_binary=@io_bazel_rules_sass//sass:sass.bzl' 107 | ]; 108 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 109 | gen = new SassGenerator(workspace); 110 | 111 | mockfs({ '/home/workspace/src': { component: { 'foo.scss': '@import "./bar";', '_bar.scss': '' } } }); 112 | 113 | // trigger the generator 114 | gen.generate(); 115 | 116 | // assert the buildozer commands are correct 117 | const commands = workspace.getBuildozer().toCommands().join('\n'); 118 | const expected = 119 | 'new_load @io_bazel_rules_sass//sass:sass.bzl sass_binary|//src/component:__pkg__\n' + 120 | 'new sass_binary foo-scss|//src/component:__pkg__\n' + 121 | 'set src "foo.scss"|//src/component:foo-scss\n' + 122 | 'add deps //src/component:bar-scss_library|//src/component:foo-scss'; 123 | 124 | expect(commands).toEqual(expected); 125 | }); 126 | }); 127 | }); 128 | -------------------------------------------------------------------------------- /src/buildozer.ts: -------------------------------------------------------------------------------- 1 | import { CommandBatch } from '@bazel/buildozer'; 2 | import { Label } from './label'; 3 | import { Rule } from './rules'; 4 | 5 | export const DEFAULT_LOAD_SITES = new Map([ 6 | ['sass_library', '@io_bazel_rules_sass//sass:sass.bzl'], 7 | ['sass_binary', '@io_bazel_rules_sass//sass:sass.bzl'], 8 | ['ts_library', '@npm//@bazel/typescript:index.bzl'], 9 | ['ng_module', '@npm//@angular/bazel:index.bzl'], 10 | ['nodejs_binary', '@build_bazel_rules_nodejs//:index.bzl'], 11 | ['container_layer', '@io_bazel_rules_docker//container:container.bzl'], 12 | ['bzl_library', '@bazel_skylib//:bzl_library.bzl'] 13 | ]); 14 | 15 | /** 16 | * Wrapper around the Buildozer used for creating and manipulating Bazel BUILD files 17 | * Provides abstractions for creating rules, adding deps etc 18 | */ 19 | export class Buildozer { 20 | private static readonly PKG = '__pkg__'; 21 | 22 | private readonly ruleLoadSites: ReadonlyMap; 23 | private readonly batchedCommands: Map = new Map(); 24 | private readonly rules: Map = new Map(); 25 | 26 | constructor(loads: Map = new Map()) { 27 | this.ruleLoadSites = this.mergeWithDefaultLoads(loads); 28 | } 29 | 30 | loadRule(type: string, label: Label) { 31 | const from = this.getRuleLoadSite(type); 32 | if (!from) { return; } 33 | 34 | this.newLoad(from, type, label); 35 | } 36 | 37 | addRule(rule: Rule) { 38 | this.rules.set(rule.label.toString(), rule); 39 | rule.toCommands(this); 40 | } 41 | 42 | newRule(rule: string, label: Label) { 43 | this.addCommand(`new ${rule} ${label.getTarget()}`, label.withTarget(Buildozer.PKG)); 44 | } 45 | 46 | addSrc(value: string[], label: Label) { 47 | this.addAttr('srcs', value, label); 48 | } 49 | 50 | addDep(dep: Array, label: Label) { 51 | this.addAttr('deps', dep.map(l => l.toString()), label); 52 | } 53 | 54 | setVisibility(visibility: string[], label: Label) { 55 | this.addAttr('visibility', visibility, label); 56 | } 57 | 58 | // lower level 59 | newLoad(from: string, symbols: string, label: Label) { 60 | if (!from) { return; } 61 | this.addCommand(`new_load ${from} ${symbols}`, label.withTarget(Buildozer.PKG)); 62 | } 63 | 64 | addAttr(attr: string, value: Array, label: Label) { 65 | this.addCommand(`add ${attr} ${value.join(' ')}`, label); 66 | } 67 | 68 | setAttr(attr: string, value: string | Label, label: Label) { 69 | this.addCommand(`set ${attr} "${value}"`, label); 70 | } 71 | 72 | removeAttr(attr: string, label: Label) { 73 | this.addCommand(`remove ${attr}`, label); 74 | } 75 | 76 | /** 77 | * Returns a CommandBatch array, suitable for passing to the @bazel/buildozer API 78 | */ 79 | toCommandBatch(): CommandBatch[] { 80 | if (!this.batchedCommands.size) { return []; } 81 | 82 | return Array.from(this.batchedCommands.entries()) 83 | .map(entry => { 84 | const target = entry[0]; 85 | const commands = entry[1]; 86 | 87 | return { commands, targets: [target] } as CommandBatch; 88 | }); 89 | } 90 | 91 | /** 92 | * Returns an array of stringy commands, suitable for writing to a file and invoking buildozer on 93 | */ 94 | toCommands(): string[] { 95 | return this.toCommandBatch() 96 | .flatMap(batch => batch.commands.map(command => `${command}|${batch.targets[0]}`)); 97 | } 98 | 99 | /** 100 | * Merges an existing buildozer instance to this one 101 | * @param buildozer 102 | */ 103 | merge(buildozer: Buildozer): Buildozer { 104 | buildozer.batchedCommands.forEach((value, key) => { 105 | if (!this.batchedCommands.has(key)) { 106 | this.batchedCommands.set(key, []); 107 | } 108 | this.batchedCommands.get(key).push(...value); 109 | }); 110 | 111 | buildozer.rules.forEach((value, key) => { 112 | this.rules.set(key, value); 113 | }); 114 | 115 | return this; 116 | } 117 | 118 | /** 119 | * Returns an added rule contained within this buildozer instance 120 | * @param label 121 | */ 122 | getRule(label: Label | string): Rule { 123 | return this.rules.get(label.toString()); 124 | } 125 | 126 | getRuleLoadSite(type: string): string { 127 | return this.ruleLoadSites.get(type); 128 | } 129 | 130 | private addCommand(command: string, label: Label) { 131 | const stringyLabel = label.toString(); 132 | if (!this.batchedCommands.has(stringyLabel)) { 133 | this.batchedCommands.set(stringyLabel, []); 134 | } 135 | 136 | this.batchedCommands.get(stringyLabel).push(command); 137 | } 138 | 139 | private mergeWithDefaultLoads(source: Map): Map { 140 | const result = new Map(source); 141 | DEFAULT_LOAD_SITES.forEach((value: string, key: string) => { 142 | if (source.has(key)) { 143 | result.set(key, source.get(key)); 144 | } else { 145 | result.set(key, value); 146 | } 147 | }); 148 | 149 | return result; 150 | } 151 | } 152 | -------------------------------------------------------------------------------- /test/workspace.spec.ts: -------------------------------------------------------------------------------- 1 | import mockfs from 'mock-fs'; 2 | 3 | import { setupAndParseArgs } from '../src/flags'; 4 | import { Workspace } from '../src/workspace'; 5 | 6 | describe('workspace', () => { 7 | let pathWorkspace: Workspace; 8 | let fileWorkspace: Workspace; 9 | 10 | beforeEach(() => { 11 | const argv = [ 12 | '--base_dir=/home/workspace', 13 | '--no-assert_is_bazel_workspace', 14 | '--label_mapping=src/baz=//other', 15 | '--label_mapping=src/foo/*=//fother' 16 | ]; 17 | 18 | const pathArgv = [ 19 | 'sass', 20 | './src/component', 21 | ...argv 22 | ]; 23 | pathWorkspace = new Workspace(setupAndParseArgs(pathArgv, true, 0)); 24 | 25 | const fileArgv = [ 26 | 'sass', 27 | './src/component/foo.component.scss', 28 | ...argv 29 | ]; 30 | fileWorkspace = new Workspace(setupAndParseArgs(fileArgv, true, 0)); 31 | 32 | // setting up the mock file system MUST come after parsing args and creating the workspace 33 | // as this part requires access to the real file system (commands are lazily required) 34 | mockfs({ 35 | '/home/workspace': { 36 | src: { 37 | component: { 38 | 'foo.component.scss': '' 39 | }, 40 | foo: { 41 | 'some-file.ts': '' 42 | }, 43 | baz: {} 44 | }, 45 | test: { 46 | bar: {} 47 | } 48 | } 49 | }); 50 | }); 51 | 52 | afterEach(() => mockfs.restore()); 53 | 54 | describe('path resolution', () => { 55 | it('resolves absolute path', () => { 56 | expect(pathWorkspace.getAbsolutePath()).toBe('/home/workspace/src/component'); 57 | expect(fileWorkspace.getAbsolutePath()).toBe('/home/workspace/src/component/foo.component.scss'); 58 | }); 59 | 60 | it('resolves path relative to the base dir', () => { 61 | expect(pathWorkspace.getPathFromBaseDir()).toBe('src/component'); 62 | expect(fileWorkspace.getPathFromBaseDir()).toBe('src/component/foo.component.scss'); 63 | }); 64 | 65 | it('resolves workspace relative path for passed path', () => { 66 | expect(pathWorkspace.resolveRelativeToWorkspace('./foo.ts')).toBe('src/component/foo.ts'); 67 | expect(fileWorkspace.resolveRelativeToWorkspace('./foo.ts')).toBe('src/component/foo.ts'); 68 | 69 | // test the following scenario: 70 | // src/component/foo.ts imports '../bar/bar.ts', fetch the workspace relative path for bar.ts to then calculate 71 | // the bazel package default label 72 | expect(pathWorkspace.resolveRelativeToWorkspace('../bar/bar.ts')).toBe('src/bar/bar.ts'); 73 | expect(fileWorkspace.resolveRelativeToWorkspace('../bar/bar.ts')).toBe('src/bar/bar.ts'); 74 | }); 75 | 76 | it('can test if path is workspace relative', () => { 77 | expect(pathWorkspace.isWorkspaceRelative('./foo.ts')).toBeFalsy(); 78 | expect(pathWorkspace.isWorkspaceRelative('../foo.ts')).toBeFalsy(); 79 | expect(pathWorkspace.isWorkspaceRelative('src/components/foo.ts')).toBeTruthy(); 80 | expect(pathWorkspace.isWorkspaceRelative('test/bar')).toBeTruthy(); 81 | expect(pathWorkspace.isWorkspaceRelative('./src/components/foo.ts')).toBeTruthy(); 82 | 83 | expect(fileWorkspace.isWorkspaceRelative('./foo.ts')).toBeFalsy(); 84 | expect(fileWorkspace.isWorkspaceRelative('../foo.ts')).toBeFalsy(); 85 | expect(fileWorkspace.isWorkspaceRelative('src/components/foo.ts')).toBeTruthy(); 86 | expect(fileWorkspace.isWorkspaceRelative('./src/components/foo.ts')).toBeTruthy(); 87 | }); 88 | 89 | it('can resolve absolute path from relative path', () => { 90 | expect(pathWorkspace.resolveAbsolute('./foo.ts')).toBe('/home/workspace/src/component/foo.ts'); 91 | expect(pathWorkspace.resolveAbsolute('foo.ts')).toBe('/home/workspace/src/component/foo.ts'); 92 | expect(fileWorkspace.resolveAbsolute('./foo.ts')).toBe('/home/workspace/src/component/foo.ts'); 93 | expect(fileWorkspace.resolveAbsolute('foo.ts')).toBe('/home/workspace/src/component/foo.ts'); 94 | 95 | expect(pathWorkspace.resolveAbsolute('../bar/bar.ts')).toBe('/home/workspace/src/bar/bar.ts'); 96 | expect(fileWorkspace.resolveAbsolute('../bar/bar.ts')).toBe('/home/workspace/src/bar/bar.ts'); 97 | }); 98 | }); 99 | 100 | describe('bazel label resolution', () => { 101 | it('can resolve path package label', () => { 102 | expect(pathWorkspace.getLabelForPath().toString()).toBe('//src/component:component'); 103 | expect(fileWorkspace.getLabelForPath().toString()).toBe('//src/component:component'); 104 | }); 105 | 106 | it('can resolve label for path', () => { 107 | expect(pathWorkspace.getLabelFor('../foo').toString()).toBe('//src/foo:foo'); 108 | expect(fileWorkspace.getLabelFor('../foo').toString()).toBe('//src/foo:foo'); 109 | 110 | expect(pathWorkspace.getLabelFor('../foo', 'bar').toString()).toBe('//src/foo:bar'); 111 | expect(fileWorkspace.getLabelFor('../foo', 'bar').toString()).toBe('//src/foo:bar'); 112 | 113 | expect(pathWorkspace.getLabelFor('foo.component.scss').toString()).toBe('//src/component:component'); 114 | expect(fileWorkspace.getLabelFor('foo.component.scss').toString()).toBe('//src/component:component'); 115 | 116 | expect(pathWorkspace.getLabelFor('src/component/foo.component.scss', 'styles').toString()).toBe('//src/component:styles'); 117 | expect(fileWorkspace.getLabelFor('src/component/foo.component.scss', 'styles').toString()).toBe('//src/component:styles'); 118 | }); 119 | 120 | it('can resolve static label mappings', () => { 121 | expect(pathWorkspace.getLabelFor('../baz').toString()).toBe('//other:other'); 122 | expect(fileWorkspace.getLabelFor('../baz').toString()).toBe('//other:other'); 123 | }); 124 | 125 | it('can resolve static label mappings with globs', () => { 126 | // without the glob this resolves to //src/foo:foo 127 | expect(pathWorkspace.getLabelFor('../foo/some-file.ts').toString()).toBe('//fother:fother'); 128 | }); 129 | 130 | it('can resolve labels for files', () => { 131 | expect(pathWorkspace.getLabelForFile('foo.component.scss', 'theme').toString()).toBe('//src/component:foo-component-theme'); 132 | expect(fileWorkspace.getLabelForFile('foo.component.scss', 'theme').toString()).toBe('//src/component:foo-component-theme'); 133 | }); 134 | }); 135 | }); 136 | -------------------------------------------------------------------------------- /test/generators/ts.generator.spec.ts: -------------------------------------------------------------------------------- 1 | import mockfs from 'mock-fs'; 2 | 3 | import { CommonFlags, setupAndParseArgs } from '../../src/flags'; 4 | import { TsGenerator } from '../../src/generators/ts/ts.generator'; 5 | import { Workspace } from '../../src/workspace'; 6 | import { TsGeneratorFlags } from '../../src/generators/ts/ts.generator.flags'; 7 | 8 | describe('ts generator', () => { 9 | const TS_ONE = 10 | `import { component } from '@angular/core'; 11 | import { Foo } from '../other/foo'; 12 | import * as r from 'rxjs/operators'; 13 | import { Observable } from 'rxjs'; 14 | 15 | export * from './two.ts'; 16 | 17 | export class Some {} 18 | `; 19 | 20 | const TS_TWO = 21 | `import { NgModule } from '@angular/core';`; 22 | 23 | let workspace: Workspace; 24 | let gen: TsGenerator; 25 | 26 | beforeEach(() => { 27 | const argv = [ 28 | 'ts', 29 | './src/some', 30 | '--base_dir=/home/workspace', 31 | '--no-assert_is_bazel_workspace', 32 | '--load_mapping=ts_library=@npm//bazel/typescript:index.bzl', 33 | '--label_mapping=rxjs/operators=@npm//rxjs', 34 | '--label_mapping=src/other/foo.ts=//mapped/label', 35 | '--ts_config_label=//:tsconfig' 36 | ]; 37 | 38 | workspace = new Workspace(setupAndParseArgs(argv, true, 0)); 39 | gen = new TsGenerator(workspace); 40 | }); 41 | 42 | afterEach(() => mockfs.restore()); 43 | 44 | it('can generate ts_library with deps', async () => { 45 | mockfs({ 46 | '/home/workspace/src/some': { 47 | 'one.ts': TS_ONE, 48 | 'two.ts': TS_TWO, 49 | 'component.component.scss': '', 50 | 'component.component.html': '', 51 | 'component.theme.scss': '' 52 | }, 53 | '/home/workspace/src/other': { 54 | 'foo.ts': '', 55 | } 56 | }); 57 | 58 | await gen.generate(); 59 | 60 | const commands = workspace.getBuildozer().toCommands(); 61 | 62 | const expected = 63 | 'new_load @npm//bazel/typescript:index.bzl ts_library|//src/some:__pkg__\n' + 64 | 'new ts_library some|//src/some:__pkg__\n' + 65 | 'add srcs one.ts two.ts|//src/some:some\n' + 66 | 'add deps @npm//@angular/core:core //mapped/label:label @npm//rxjs:rxjs|//src/some:some\n' + 67 | 'set tsconfig "//:tsconfig"|//src/some:some'; 68 | 69 | expect(commands.join('\n')).toEqual(expected); 70 | }); 71 | 72 | it('can handle imports with double and single quotes', async () => { 73 | mockfs({ 74 | '/home/workspace/src/some': { 75 | 'one.ts': 'import { NgModule } from "@angular/core";\nimport * as r from \'rxjs/operators\'', 76 | 'component.component.scss': '', 77 | 'component.component.html': '', 78 | 'component.theme.scss': '' 79 | }, 80 | '/home/workspace/src/other': { 81 | 'foo.ts': '', 82 | } 83 | }); 84 | 85 | await gen.generate(); 86 | 87 | const commands = workspace.getBuildozer().toCommands(); 88 | 89 | const expected = 90 | 'new_load @npm//bazel/typescript:index.bzl ts_library|//src/some:__pkg__\n' + 91 | 'new ts_library some|//src/some:__pkg__\n' + 92 | 'add srcs one.ts|//src/some:some\n' + 93 | 'add deps @npm//@angular/core:core @npm//rxjs:rxjs|//src/some:some\n' + 94 | 'set tsconfig "//:tsconfig"|//src/some:some'; 95 | 96 | expect(commands.join('\n')).toEqual(expected); 97 | }); 98 | 99 | it('can use tsconfig paths', async () => { 100 | mockfs({ 101 | '/home/workspace': { 102 | 'tsconfig.json': `{"compilerOptions":{"paths":{"@foo/*":["src/some/nested/*"]}}}`, 103 | src: { 104 | some: { 105 | nested: { 106 | 'main.ts': '' 107 | }, 108 | 'one.ts': `import { BAR } from '@foo/main'`, 109 | } 110 | } 111 | }, 112 | }); 113 | 114 | (workspace.getFlags() as TsGeneratorFlags).ts_config = 'tsconfig.json'; 115 | gen = new TsGenerator(workspace); 116 | 117 | await gen.generate(); 118 | 119 | const commands = workspace.getBuildozer().toCommands(); 120 | 121 | const expected = 122 | 'new_load @npm//bazel/typescript:index.bzl ts_library|//src/some:__pkg__\n' + 123 | 'new ts_library some|//src/some:__pkg__\n' + 124 | 'add srcs one.ts|//src/some:some\n' + 125 | 'add deps //src/some/nested:nested|//src/some:some\n' + 126 | 'set tsconfig "//:tsconfig"|//src/some:some'; 127 | 128 | expect(commands.join('\n')).toEqual(expected); 129 | }); 130 | 131 | it('can strip all deep imports', async () => { 132 | mockfs({ 133 | '/home/workspace/src/some': { 134 | 'one.ts': `import {} from 'package'; import {} from 'package/deep'; import {} from '@scope/package'; import {} from '@scope/package/deep';` 135 | }, 136 | },); 137 | 138 | await gen.generate(); 139 | 140 | const commands = workspace.getBuildozer().toCommands(); 141 | 142 | const expected =`new_load @npm//bazel/typescript:index.bzl ts_library|//src/some:__pkg__ 143 | new ts_library some|//src/some:__pkg__ 144 | add srcs one.ts|//src/some:some 145 | add deps @npm//package:package @npm//@scope/package:package|//src/some:some 146 | set tsconfig "//:tsconfig"|//src/some:some`; 147 | 148 | expect(commands.join('\n')).toEqual(expected); 149 | }); 150 | 151 | it('converts builtin imports for node types', async () => { 152 | mockfs({ 153 | '/home/workspace/src/some': { 154 | 'one.ts': `import * as fs from 'fs';` 155 | }, 156 | },); 157 | 158 | await gen.generate(); 159 | 160 | const commands = workspace.getBuildozer().toCommands(); 161 | 162 | const expected =`new_load @npm//bazel/typescript:index.bzl ts_library|//src/some:__pkg__ 163 | new ts_library some|//src/some:__pkg__ 164 | add srcs one.ts|//src/some:some 165 | add deps @npm//@types/node:node|//src/some:some 166 | set tsconfig "//:tsconfig"|//src/some:some`; 167 | 168 | expect(commands.join('\n')).toEqual(expected); 169 | }); 170 | 171 | it('can set default package label as dep', async () => { 172 | mockfs({ 173 | '/home/workspace/src/some': { 174 | 'one.ts': `import {SOME_CONST} from './nested/two'; ` 175 | }, 176 | '/home/workspace/src/some/nested': { 177 | 'two.ts': `export const SOME_CONST = '';` 178 | } 179 | }); 180 | 181 | (workspace.getFlags() as CommonFlags).pkg_default_dep_labels = true; 182 | 183 | await gen.generate(); 184 | 185 | const commands = workspace.getBuildozer().toCommands(); 186 | 187 | const expected =`new_load @npm//bazel/typescript:index.bzl ts_library|//src/some:__pkg__ 188 | new ts_library some|//src/some:__pkg__ 189 | add srcs one.ts|//src/some:some 190 | add deps //src/some/nested:nested|//src/some:some 191 | set tsconfig "//:tsconfig"|//src/some:some`; 192 | 193 | expect(commands.join('\n')).toEqual(expected); 194 | }); 195 | 196 | it('can set file as dep label', async () => { 197 | mockfs({ 198 | '/home/workspace/src/some': { 199 | 'one.ts': `import {SOME_CONST} from './nested/two'; ` 200 | }, 201 | '/home/workspace/src/some/nested': { 202 | 'two.ts': `export const SOME_CONST = '';` 203 | } 204 | }); 205 | 206 | (workspace.getFlags() as CommonFlags).pkg_default_dep_labels = false; 207 | 208 | await gen.generate(); 209 | 210 | const commands = workspace.getBuildozer().toCommands(); 211 | 212 | const expected =`new_load @npm//bazel/typescript:index.bzl ts_library|//src/some:__pkg__ 213 | new ts_library some|//src/some:__pkg__ 214 | add srcs one.ts|//src/some:some 215 | add deps //src/some/nested:two|//src/some:some 216 | set tsconfig "//:tsconfig"|//src/some:some`; 217 | 218 | expect(commands.join('\n')).toEqual(expected); 219 | }); 220 | 221 | }); 222 | -------------------------------------------------------------------------------- /src/generators/ts/ts.generator.ts: -------------------------------------------------------------------------------- 1 | import { existsSync } from 'fs'; 2 | import { join, parse, posix } from 'path'; 3 | import { tsquery } from '@phenomnomnominal/tsquery'; 4 | import Builtins from 'builtins'; 5 | import { createMatchPath, MatchPath } from 'tsconfig-paths'; 6 | import { 7 | ExportDeclaration, 8 | Expression, 9 | ImportDeclaration, 10 | ParseConfigHost, 11 | parseJsonSourceFileConfigFileContent, 12 | readJsonConfigFile, 13 | SourceFile, 14 | sys 15 | } from 'typescript'; 16 | 17 | import { Flags } from '../../flags'; 18 | import { Label } from '../../label'; 19 | import { log } from '../../logger'; 20 | import { Workspace } from '../../workspace'; 21 | import { BuildFileGenerator } from '../generator'; 22 | import { Generator } from '../resolve-generator'; 23 | import { GeneratorType } from '../types'; 24 | import { TsGeneratorFlags } from './ts.generator.flags'; 25 | import { Rule, SingleAttrValue } from '../../rules'; 26 | 27 | const IMPORTS_QUERY = `ImportDeclaration:has(StringLiteral)`; 28 | const EXPORTS_QUERY = `ExportDeclaration:has(StringLiteral)`; 29 | 30 | class TsLibraryRule extends Rule { 31 | constructor(label: Label) { 32 | super('ts_library', label); 33 | } 34 | 35 | setTsConfig(tsconfig: SingleAttrValue): this { 36 | this.setAttr('tsconfig', tsconfig); 37 | return this; 38 | } 39 | } 40 | 41 | @Generator({ 42 | type: 'ts', 43 | description: 'Generates a ts_library for the files or file at path', 44 | flags: TsGeneratorFlags 45 | }) 46 | export class TsGenerator extends BuildFileGenerator { 47 | protected readonly tsPathsMatcher: MatchPath; 48 | protected readonly builtins: string[] = []; 49 | protected readonly flags: Flags; 50 | 51 | constructor(workspace: Workspace) { 52 | super(workspace); 53 | this.flags = this.getFlags(); 54 | 55 | this.builtins = Builtins(); 56 | this.tsPathsMatcher = this.createPathMatcherForTsPaths(); 57 | } 58 | 59 | async generate(): Promise { 60 | const files = this.workspace.isDirectory() ? this.workspace.readDirectory() : [this.workspace.getPath()]; 61 | 62 | const tsFiles = files 63 | .filter(file => file.endsWith('.ts')) 64 | .filter(file => !(this.flags.ignore_spec_files && file.endsWith('.spec.ts'))); 65 | 66 | const deps = new Set(); 67 | tsFiles 68 | .forEach(file => this.processFile(file, tsFiles, this.flags.npm_workspace_name, deps)); 69 | 70 | const label = this.workspace.isDirectory() ? this.workspace.getLabelForPath() : 71 | this.workspace.getLabelForPath().withTarget(this.workspace.getPathInfo().name); 72 | 73 | const tsLibrary = new TsLibraryRule(label) 74 | .setSrcs(tsFiles.map(path => parse(path).base)) 75 | .setDeps(Array.from(deps)); 76 | 77 | if (this.flags.ts_config_label) { 78 | tsLibrary.setTsConfig(this.flags.ts_config_label); 79 | } 80 | 81 | this.setDefaultVisibility(tsLibrary); 82 | this.buildozer.addRule(tsLibrary); 83 | } 84 | 85 | getGeneratorType(): GeneratorType { 86 | return GeneratorType.TS; 87 | } 88 | 89 | supportsDirectories(): boolean { 90 | return true; 91 | } 92 | 93 | protected processFile(filePath: string, tsFiles: string[], npmWorkspace: string, labels: Set): Set { 94 | const file = this.workspace.readFile(filePath); 95 | const ast = tsquery.ast(file); 96 | 97 | return this.processTsFileAst(ast, tsFiles, npmWorkspace, labels); 98 | } 99 | 100 | protected processTsFileAst(ast: SourceFile, tsFiles: string[], npmWorkspace: string, labels: Set): Set { 101 | tsquery(ast, IMPORTS_QUERY) 102 | .map((node: ImportDeclaration) => this.resolveLabelFromModuleSpecifier(node.moduleSpecifier, tsFiles, npmWorkspace)) 103 | .filter(label => !!label) 104 | .forEach(label => labels.add(label.toString())); 105 | 106 | tsquery(ast, EXPORTS_QUERY) 107 | .map((node: ExportDeclaration) => this.resolveLabelFromModuleSpecifier(node.moduleSpecifier, tsFiles, npmWorkspace)) 108 | .filter(label => !!label) 109 | .forEach(label => labels.add(label.toString())); 110 | 111 | return labels; 112 | } 113 | 114 | private resolveLabelFromModuleSpecifier(moduleSpecifier: Expression, tsFiles: string[] = [], npmWorkspace: string): Label | undefined { 115 | const moduleSpecifierText = moduleSpecifier.getText().replace(/['"]+/g, ''); 116 | const workspaceRelativeImport = this.workspace.resolveRelativeToWorkspace(moduleSpecifierText); 117 | if ( 118 | tsFiles.includes( 119 | workspaceRelativeImport.endsWith('.ts') ? workspaceRelativeImport : workspaceRelativeImport + '.ts') 120 | ) { 121 | return; 122 | } 123 | 124 | const label = this.calculateTsDependencyLabel(moduleSpecifierText, npmWorkspace); 125 | 126 | if (this.workspace.getFlags().verbose_import_mappings) { 127 | log(`${moduleSpecifierText}=${label}`); 128 | } 129 | 130 | return label; 131 | } 132 | 133 | private calculateTsDependencyLabel(imp: string, npmWorkspace: string): Label | undefined { 134 | // see if there is a tsconfig.json, and if we need to adjust the import 135 | imp = this.tryResolveFromTsPaths(imp); 136 | 137 | let label = this.workspace.tryResolveLabelFromStaticMapping(imp, undefined, '.'); 138 | if (label) { return label; } 139 | 140 | // if the module is a builtin, return @types/node 141 | // if the import had been overridden it should have happened above 142 | if (this.builtins.includes(imp)) { 143 | return Label.parseAbsolute(`@${npmWorkspace}//@types/node`); 144 | } 145 | 146 | const relative = this.workspace.isWorkspaceRelative(imp) || imp.startsWith('.'); 147 | 148 | if (relative) { 149 | const index = join(imp, 'index.ts'); 150 | if (existsSync(this.workspace.resolveAbsolute(index))) { 151 | label = this.workspace.getLabelForFile(index); 152 | } else { 153 | label = this.workspace.getLabelForFile(imp + '.ts'); 154 | } 155 | 156 | if (label) { 157 | return this.flags.pkg_default_dep_labels ? label.asDefaultLabel() : label; 158 | } 159 | 160 | throw new Error (`Unable to generate label for: ${imp}`) 161 | } else { 162 | // module specifiers do not use system seperators 163 | // they always use forward slashes 164 | const pathParts = imp.split(posix.sep); 165 | // remove any deep imports by stripping any paths past the end of the package name 166 | let reducedPathed: string; 167 | if(imp.startsWith('@')) { 168 | // a scoped npm package cannot have more than two segments 169 | reducedPathed = posix.join(...pathParts.slice(0, 2)); 170 | } else { 171 | // a normal npm package cannot have more than one segment 172 | reducedPathed = posix.join(...pathParts.slice(0, 1)); 173 | 174 | } 175 | return Label.parseAbsolute(`@${npmWorkspace}//${reducedPathed}`); 176 | } 177 | } 178 | 179 | private tryResolveFromTsPaths(imp: string): string { 180 | if (!this.tsPathsMatcher) { 181 | return imp; 182 | } 183 | 184 | const path = this.tsPathsMatcher(imp, undefined, undefined, ['.ts']); 185 | return path ? path.replace(this.workspace.getFlags().base_dir + '/', '') : imp; 186 | } 187 | 188 | private createPathMatcherForTsPaths(): MatchPath | undefined { 189 | if (!this.flags.ts_config) { 190 | return; 191 | } 192 | 193 | const tsconfigPath = this.workspace.resolveRelativeToWorkspace(this.flags.ts_config); 194 | const tsConfigSourceFile = readJsonConfigFile(tsconfigPath, path => this.workspace.readFile(path)); 195 | 196 | if (!tsConfigSourceFile) { 197 | throw new Error(`--ts_config flag set, but failed to load tsconfig.json from ${tsconfigPath}`); 198 | } 199 | 200 | const parseConfigHost: ParseConfigHost = { 201 | fileExists: sys.fileExists, 202 | readFile: path => this.workspace.readFile(path), 203 | readDirectory: sys.readDirectory, 204 | useCaseSensitiveFileNames: true 205 | }; 206 | 207 | const parsed = parseJsonSourceFileConfigFileContent(tsConfigSourceFile, parseConfigHost, this.workspace.getPath()); 208 | 209 | // we _could_ throw parse errors here, but it may be not worth it if we can access the paths attr 210 | if (!parsed.options.paths) { 211 | return; 212 | } 213 | 214 | return createMatchPath(this.flags.base_dir, parsed.options.paths); 215 | } 216 | } 217 | -------------------------------------------------------------------------------- /src/flags.ts: -------------------------------------------------------------------------------- 1 | import { isAbsolute, join, resolve } from 'path'; 2 | import yargs, { Options } from 'yargs'; 3 | 4 | import { GENERATORS } from './generators/resolve-generator'; 5 | import { debug, fatal, lb } from './logger'; 6 | import { GeneratorType } from './generators'; 7 | import { lstatSync, readFileSync } from 'fs'; 8 | 9 | const RC_FILE_NAME = '.bzlgenrc'; 10 | 11 | const parser = yargs 12 | .help() 13 | .wrap(yargs.terminalWidth()) 14 | .recommendCommands() 15 | .scriptName('bzlgen') 16 | .demandCommand() 17 | .version(); 18 | 19 | function coerceMappingFlag(loads: string[]): Map { 20 | const items: Array<[string, string]> = loads 21 | .map(load => load.split('=') as [string, string]); 22 | return new Map(items); 23 | } 24 | 25 | export function Flag(options: Options & { global?: boolean }) { 26 | return (container, prop) => { 27 | const group = container.constructor.name.split('Flags')[0].match(/[A-Z][a-z]+/).join(' '); 28 | 29 | const parserOption = { 30 | ...options, 31 | group: options.group ?? group, 32 | }; 33 | 34 | if (options.global) { 35 | parser.option(prop, parserOption); 36 | } else { 37 | const holder = container.$Flags ?? {}; 38 | holder[prop] = parserOption; 39 | container.$Flags = holder; 40 | } 41 | }; 42 | } 43 | 44 | function GlobalFlag(options: Options) { 45 | return (container, prop) => Flag({ ...options, global: true })(container, prop); 46 | } 47 | 48 | 49 | export const setupAndParseArgs = (argv: any[], ignorerc: boolean = false, strip = 2): Flags => { 50 | const ARGS = [...argv].slice(strip); 51 | const isDebug = ARGS.includes('--debug'); 52 | 53 | if (!ignorerc) { 54 | try { 55 | // if we are running under bazel, then load the rc file using the runfiles helper 56 | let rcpath = RC_FILE_NAME; 57 | const runfilesHelper = process.env.BAZEL_NODE_RUNFILES_HELPER; 58 | if (runfilesHelper) { 59 | const f = require(runfilesHelper); 60 | rcpath = (f.manifest as Map).get(`${process.env.BAZEL_WORKSPACE}/${RC_FILE_NAME}`); 61 | } 62 | 63 | if (lstatSync(rcpath).isFile()) { 64 | if (isDebug) { 65 | debug(`Loading args from ${rcpath}`); 66 | } 67 | 68 | const rc = readFileSync(RC_FILE_NAME, { encoding: 'utf-8' }) 69 | .split('\n') 70 | .filter(t => !t.startsWith('#') && !!t) 71 | .map(t => t.trim()); 72 | 73 | ARGS.splice(2, 0, ...rc); 74 | } 75 | } catch (e) { 76 | // probably no rc file 77 | } 78 | } 79 | 80 | if (isDebug) { 81 | debug('Parsing argv:'); 82 | debug(ARGS.join(' ')); 83 | lb(); 84 | } 85 | 86 | GENERATORS.forEach(command => { 87 | parser.command({ 88 | command: `${command.type} `, 89 | desc: command.description, 90 | builder: y => { 91 | if (command.flags) { 92 | const cFlags = Array.isArray(command.flags) ? command.flags : [command.flags]; 93 | cFlags.map(cF => cF.prototype).forEach(f => { 94 | Object.keys(f.$Flags).forEach(flag => y.option(flag, f.$Flags[flag])); 95 | }); 96 | } 97 | 98 | y.positional('path', { 99 | describe: 'Relative path to the directory or file to generate for', 100 | type: 'string', 101 | normalize: true, 102 | coerce: (arg: string) => { 103 | // simple check, not comprehensive but catches most users 104 | if (arg.startsWith('..')) { 105 | fatal('Path must not attempt to escape base_dir'); 106 | } 107 | if (arg.endsWith('/')) { 108 | arg = arg.substr(0, arg.length - 1); 109 | } 110 | return arg; 111 | } 112 | }); 113 | 114 | return y; 115 | }, 116 | handler: args => { 117 | args.type = command.type; 118 | if (command.implies) { 119 | Object.keys(command.implies).forEach(imp => args[imp] = command.implies[imp]); 120 | } 121 | } 122 | }); 123 | }); 124 | 125 | return parser.parse(ARGS) as Flags; 126 | }; 127 | 128 | export abstract class InternalFlags { 129 | @GlobalFlag({ 130 | description: 'The binary or path to a binary to use for "bazel"', 131 | type: 'string', 132 | default: 'bazel' 133 | }) 134 | bazel_binary: boolean; 135 | } 136 | 137 | export abstract class LoggingFlags { 138 | @GlobalFlag({ 139 | description: 'If set, print the value of all flags with defaults and exit', 140 | type: 'boolean', 141 | default: false 142 | }) 143 | canonicalize_flags: boolean; 144 | 145 | @GlobalFlag({ 146 | description: 'Log extra info when calculating import label mappings', 147 | type: 'boolean', 148 | default: false 149 | }) 150 | verbose_import_mappings: boolean; 151 | 152 | @GlobalFlag({ 153 | description: 'Enables debug logging', 154 | type: 'boolean', 155 | default: false, 156 | implies: ['canonicalize_flags'] 157 | }) 158 | debug: boolean; 159 | 160 | @GlobalFlag({ 161 | description: 'Output commands to the console before invoking buildozer', 162 | type: 'boolean', 163 | default: false 164 | }) 165 | output_buildozer_to_console: boolean; 166 | } 167 | 168 | export abstract class CommonFlags { 169 | /** 170 | * Type of rule to expect to generate 171 | * The generator may error if the expected type doesn't match files found 172 | */ 173 | type: GeneratorType; 174 | 175 | /** 176 | * Relative path to the directory or file to generate for 177 | */ 178 | path: string; 179 | 180 | @GlobalFlag({ 181 | description: 'A glob pattern that is applied to the files at path when path represents a directory', 182 | type: 'string' 183 | }) 184 | pattern: string; 185 | 186 | @GlobalFlag({ 187 | description: 'Remove the existing build file before creating the new one', 188 | type: 'boolean', 189 | default: false 190 | }) 191 | nuke_build_file: boolean; 192 | 193 | @GlobalFlag({ 194 | description: 'Checks if the base_dir is a bazel workspace, and if not throws an error', 195 | type: 'boolean', 196 | default: true 197 | }) 198 | assert_is_bazel_workspace: boolean; 199 | 200 | @GlobalFlag({ 201 | description: 'Base dir that is prefixed to \'path\' to form an absolute path', 202 | type: 'string', 203 | default: process.env.BUILD_WORKSPACE_DIRECTORY ?? process.cwd(), 204 | coerce: arg => { 205 | return isAbsolute(arg) ? arg : 206 | process.env.BUILD_WORKSPACE_DIRECTORY ? 207 | join(process.env.BUILD_WORKSPACE_DIRECTORY, arg) : resolve(process.cwd(), arg); 208 | }, 209 | requiresArg: true, 210 | }) 211 | base_dir: string; 212 | 213 | @GlobalFlag({ 214 | description: 'Separator character to use when generating targets', 215 | type: 'string', 216 | default: '-', 217 | requiresArg: true 218 | }) 219 | suffix_separator: string; 220 | 221 | @GlobalFlag({ 222 | description: 'Additional label mappings in the form ../some/file/path.js=//some/label:target', 223 | type: 'array', 224 | default: [], 225 | requiresArg: true, 226 | coerce: coerceMappingFlag 227 | }) 228 | label_mapping: Map; 229 | 230 | @GlobalFlag({ 231 | description: 'Additional load sites or overrides for existing rules parsed in the form ts_library=//some/path/to/defs.bzl', 232 | type: 'array', 233 | default: [], 234 | requiresArg: true, 235 | coerce: coerceMappingFlag 236 | }) 237 | load_mapping: Map; 238 | 239 | @GlobalFlag({ 240 | description: 241 | 'Only calculate a files dependencies and output them as labels to the console. ' + 242 | 'Don\'t generate any BUILD files or buildozer commands', 243 | type: 'boolean', 244 | default: false 245 | }) 246 | only_deps: boolean; 247 | 248 | @GlobalFlag({ 249 | description: 'Create missing BUILD files and invoke buildozer', 250 | type: 'boolean', 251 | default: true 252 | }) 253 | generate_build_files: boolean; 254 | 255 | @GlobalFlag({ 256 | description: 'Name to use for bazel build files, eg BUILD or BUILD.bazel', 257 | type: 'string', 258 | default: 'BUILD', 259 | choices: ['BUILD', 'BUILD.bazel'] 260 | }) 261 | build_file_name: string; 262 | 263 | @GlobalFlag({ 264 | description: 265 | 'When generating best guess dependency labels, treat the dependency labels as though there is a BUILD file for each ' + 266 | 'directory and use the package default label - //my/package:package ' + 267 | 'If false, then the filename is considered to be the target for the dependency label - //my/package:main', 268 | type: 'boolean', 269 | default: true 270 | }) 271 | pkg_default_dep_labels: boolean; 272 | 273 | @GlobalFlag({ 274 | description: 'Ignores spec / test files and does not generate rules for them', 275 | type: 'boolean', 276 | default: true, 277 | deprecated: true 278 | }) 279 | /** 280 | * @deprecated 281 | */ 282 | ignore_spec_files: boolean; 283 | 284 | @GlobalFlag({ 285 | description: 'Default visibility to set on rules', 286 | type: 'string', 287 | default: '' 288 | }) 289 | default_visibility: string; 290 | } 291 | 292 | export abstract class ExperimentalFlags { 293 | @GlobalFlag({ 294 | description: 'Use bazel query to determine a source files label. ' + 295 | 'If the label can\'t be resolved via query, bzlgen will fall back to the best guess. ' + 296 | 'Label mappings will always be resolved first', 297 | type: 'boolean', 298 | default: false 299 | }) 300 | use_bazel_query: boolean; 301 | } 302 | 303 | export type Flags = 304 | Readonly; 305 | -------------------------------------------------------------------------------- /src/generators/ng/ng.generator.ts: -------------------------------------------------------------------------------- 1 | import { tsquery } from '@phenomnomnominal/tsquery'; 2 | import { parse } from 'path'; 3 | import { StringLiteral } from 'typescript'; 4 | import { Label } from '../../label'; 5 | 6 | import { fatal, warn } from '../../logger'; 7 | import { ArrayAttrValue, Rule, SingleAttrValue } from '../../rules'; 8 | import { Workspace } from '../../workspace'; 9 | import { Generator } from '../resolve-generator'; 10 | import { SassBinaryRule, SassGenerator } from '../sass/sass.generator'; 11 | import { TsGenerator } from '../ts/ts.generator'; 12 | import { GeneratorType } from '../types'; 13 | import { NgGeneratorFlags } from './ng.generator.flags'; 14 | import { TsGeneratorFlags } from '../ts/ts.generator.flags'; 15 | 16 | const STYLE_URLS_QUERY = 'Decorator:has(Decorator > CallExpression[expression.name="Component"]) PropertyAssignment:has([name="styleUrls"]) ArrayLiteralExpression StringLiteral'; 17 | const TEMPLATE_URL_QUERY = 'Decorator:has(Decorator > CallExpression[expression.name="Component"]) PropertyAssignment:has([name="templateUrl"]) StringLiteral'; 18 | 19 | type TsFileResultContainer = { 20 | tsDeps: Set 21 | styles: Map, name: string }> 22 | assets: Set 23 | }; 24 | 25 | class NgModuleRule extends Rule { 26 | constructor(label: Label, load?: string) { 27 | super('ng_module', label, load); 28 | } 29 | 30 | setAssets(assets: ArrayAttrValue): this { 31 | this.setAttr('assets', assets); 32 | return this; 33 | } 34 | 35 | // for ng_module bundles 36 | setStyle(style: SingleAttrValue): this { 37 | this.setAttr('style', style); 38 | return this; 39 | } 40 | 41 | setStyleDeps(deps: ArrayAttrValue): this { 42 | this.setAttr('style_deps', deps); 43 | return this; 44 | } 45 | 46 | setTheme(theme: SingleAttrValue): this { 47 | this.setAttr('theme', theme); 48 | return this; 49 | } 50 | 51 | setThemeDeps(deps: ArrayAttrValue): this { 52 | this.setAttr('theme_deps', deps); 53 | return this; 54 | } 55 | } 56 | 57 | @Generator({ 58 | type: GeneratorType.NG, 59 | flags: [NgGeneratorFlags, TsGeneratorFlags], 60 | description: 'Generates a ng_module rule for an Angular component' 61 | }) 62 | @Generator({ 63 | type: GeneratorType.NG_BUNDLE, 64 | flags: [NgGeneratorFlags, TsGeneratorFlags], 65 | description: 'Generates a ng_module macro rule for an Angular component' 66 | }) 67 | export class NgGenerator extends TsGenerator { 68 | 69 | constructor(readonly workspace: Workspace) { 70 | super(workspace); 71 | } 72 | 73 | async generate(): Promise { 74 | const files = this.workspace.readDirectory(); 75 | 76 | const tsFiles = files 77 | .filter(file => file.endsWith('.ts')) 78 | .filter(file => !(this.flags.ignore_spec_files && file.endsWith('.spec.ts'))); 79 | 80 | const resultContainer: TsFileResultContainer = { 81 | tsDeps: new Set(), 82 | styles: new Map(), 83 | assets: new Set() 84 | }; 85 | 86 | tsFiles 87 | .forEach((file, i, arr) => this.processTsFile(file, arr, this.flags.npm_workspace_name, this.flags.suffix_separator, resultContainer)); 88 | 89 | if (this.getGeneratorType() === GeneratorType.NG) { 90 | this.generateNgModule(files, tsFiles, resultContainer); 91 | } else { 92 | this.generateNgModuleBundle(files, tsFiles, resultContainer); 93 | } 94 | } 95 | 96 | getGeneratorType(): GeneratorType { 97 | return this.workspace.getFlags().type; 98 | } 99 | 100 | supportsDirectories(): boolean { 101 | return true; 102 | } 103 | 104 | validate(): boolean { 105 | if (!this.workspace.isDirectory()) { 106 | fatal('Path passed to Angular generator must be a directory'); 107 | } 108 | 109 | return true; 110 | } 111 | 112 | private processTsFile(filePath: string, tsFiles: string[], npmWorkspace: string, suffixSeparator: string, 113 | resultContainer: TsFileResultContainer) { 114 | const file = this.workspace.readFile(filePath); 115 | const ast = tsquery.ast(file); 116 | 117 | this.processTsFileAst(ast, tsFiles, npmWorkspace, resultContainer.tsDeps); 118 | 119 | const templateUrlNode = tsquery(ast, TEMPLATE_URL_QUERY)[0] as StringLiteral; 120 | 121 | if (templateUrlNode && templateUrlNode.text.startsWith('./')) { 122 | const url = templateUrlNode.text; 123 | const splits = url.split('/'); 124 | 125 | if (splits.length === 2 || splits.length === 0) { 126 | // TODO(matt) internally there are some templates that pull from the parent directory 127 | // and bzl gen handles it in a hacky way - don't port this behaviour yet 128 | // additionally - ensure that the path only contains one (or none) '/', meaning that it's in the same package 129 | 130 | // we don't need a label for the html file, but we do need to strip a leading './' if present 131 | resultContainer.assets.add(templateUrlNode.text.replace(/\.\//, '')); 132 | } 133 | } 134 | 135 | const styleUrlsNodes = tsquery(ast, STYLE_URLS_QUERY) as StringLiteral[]; 136 | 137 | if (styleUrlsNodes && styleUrlsNodes.length) { 138 | const abstractStyles = styleUrlsNodes 139 | .map(node => node.text) 140 | .filter(text => text.startsWith('..')); 141 | 142 | if (abstractStyles.length) { 143 | // the component has a style imported from a parent directory 144 | // we can't generate files into the parent directory under bazel, so throw an error here 145 | // showing the user how this can be fixed 146 | const message = `The Angular component in file ${ filePath } contains a reference ` + 147 | `to the following style sheets imported from the parent directory:\n\t${ abstractStyles.join('\n\t') }\n` + 148 | `These will not be included in the generated ${ this.flags.build_file_name } file and will need to be manually added ` + 149 | `or, imported via @import in a scss file`; 150 | warn(message); 151 | } 152 | 153 | const scssFiles = styleUrlsNodes 154 | .map(node => node.text) 155 | .filter(text => text.startsWith('./')); 156 | 157 | const sassGen = new SassGenerator(this.workspace); 158 | resultContainer.styles = this.calculateScssDependencyLabels(scssFiles, sassGen, suffixSeparator, 'styles'); 159 | } 160 | } 161 | 162 | private calculateScssDependencyLabels(scssFiles: string[], sassGen: SassGenerator, suffixSeparator: string, 163 | labelSuffix: string): Map, name: string }> { 164 | if (!scssFiles.length) { return new Map(); } 165 | 166 | const results = new Map, name: string }>(); 167 | scssFiles 168 | .forEach(path => { 169 | const file = this.workspace.readFile(path); 170 | const labels = sassGen.calculateDeps(file, false) 171 | .map(imp => sassGen.calculateDependencyLabel(imp, labelSuffix)); 172 | 173 | const name = sassGen.calculateDependencyLabel(path, labelSuffix); 174 | 175 | results.set( 176 | path 177 | .replace(/'/g, '') 178 | .replace(/"/g, '') 179 | .replace(/\.\//g, ''), { deps: new Set(labels), name } 180 | ); 181 | }); 182 | 183 | return results; 184 | } 185 | 186 | private generateNgModule(allFiles: string[], tsFiles: string[], resultContainer: TsFileResultContainer) { 187 | const flags = this.workspace.getFlags(); 188 | 189 | const styleRules = Array.from(resultContainer.styles.values()) 190 | .map(value => value.name); 191 | 192 | // generate the ng_module 193 | const ngModuleRule = new NgModuleRule(this.workspace.getLabelForPath()) 194 | .setSrcs(tsFiles.map(file => file.split('/').pop())) 195 | .setDeps(Array.from(resultContainer.tsDeps)) 196 | .setAssets(Array.from(resultContainer.assets).concat(styleRules)); 197 | 198 | this.setDefaultVisibility(ngModuleRule); 199 | 200 | this.buildozer.addRule(ngModuleRule); 201 | 202 | // generate the sass_binary for styles 203 | resultContainer.styles.forEach((data, src) => { 204 | const sassBinaryRule = new SassBinaryRule(this.workspace.getLabelForPath().withTarget(data.name.split(':')[1])) 205 | .setSrc(src) 206 | .setDeps(Array.from(data.deps)); 207 | 208 | this.buildozer.addRule(sassBinaryRule); 209 | // TODO(matt): if there are deps on a sass import in the same package we should be able to generate it here 210 | }); 211 | 212 | if (this.getFlags().ng_generate_theme_binary) { 213 | const themeFiles = allFiles.filter(file => file.endsWith('.theme.scss') && !file.startsWith('_')); 214 | const themes = this.calculateScssDependencyLabels(themeFiles, new SassGenerator(this.workspace), flags.suffix_separator, 'theme'); 215 | 216 | themes.forEach((data, src) => { 217 | const sassBinaryRule = new SassBinaryRule(this.workspace.getLabelForPath().withTarget(data.name.split(':')[1])) 218 | .setSrc(parse(src).base) 219 | .setDeps(Array.from(data.deps)); 220 | this.buildozer.addRule(sassBinaryRule); 221 | }); 222 | } 223 | } 224 | 225 | private generateNgModuleBundle(allFiles: string[], tsFiles: string[], resultContainer: TsFileResultContainer) { 226 | const pathLabel = this.workspace.getLabelForPath(); 227 | const flags = this.getFlags(); 228 | 229 | const deps = Array.from(resultContainer.tsDeps) 230 | .filter(dep => !(dep.endsWith('@angular/core:core') || dep.endsWith('@angular/common:common') || dep.endsWith('rxjs:rxjs'))); 231 | 232 | const ngModuleBundleRule = new NgModuleRule(pathLabel, flags.ng_module_bundle_load) 233 | .setSrcs(tsFiles.map(file => file.split('/').pop())) 234 | .setDeps(deps); 235 | 236 | if (resultContainer.styles.size) { 237 | // ng_module macro only supports one style 238 | const style = Array.from(resultContainer.styles.entries())[0]; 239 | ngModuleBundleRule.setStyle(style[0]); 240 | 241 | if (style[1].deps.size) { 242 | ngModuleBundleRule.setStyleDeps(Array.from(style[1].deps)); 243 | } 244 | } 245 | 246 | if (resultContainer.assets.size) { 247 | ngModuleBundleRule.setAssets(Array.from(resultContainer.assets)); 248 | } 249 | 250 | if (flags.ng_generate_theme_binary) { 251 | const themeFiles = allFiles.filter(file => file.endsWith('.theme.scss') && !file.startsWith('_')); 252 | if (themeFiles.length) { 253 | const themes = this.calculateScssDependencyLabels(themeFiles, new SassGenerator(this.workspace), flags.suffix_separator, 'theme'); 254 | ngModuleBundleRule.setTheme(themeFiles[0].split('/').pop()); 255 | 256 | const theme = themes.get(themeFiles[0]); 257 | if (theme.deps.size) { 258 | ngModuleBundleRule.setThemeDeps(Array.from(theme.deps)); 259 | } 260 | } 261 | } 262 | 263 | this.buildozer.addRule(ngModuleBundleRule); 264 | } 265 | } 266 | -------------------------------------------------------------------------------- /src/workspace.ts: -------------------------------------------------------------------------------- 1 | import { lstatSync, readdirSync, readFileSync } from 'fs'; 2 | import kebabCase from 'lodash.kebabcase'; 3 | import { isAbsolute, join, normalize, parse, ParsedPath, sep } from 'path'; 4 | import * as shell from 'shelljs'; 5 | import * as util from 'util'; 6 | import minimatch from 'minimatch'; 7 | import * as BazelBuildozer from '@bazel/buildozer'; 8 | 9 | import { Buildozer } from './buildozer'; 10 | import { Flags } from './flags'; 11 | import { Label } from './label'; 12 | import { debug, fatal, isDebugEnabled, lb, log, warn } from './logger'; 13 | 14 | export class Workspace { 15 | private static readonly QUERY_FLAGS = `--output label --order_output=no`; 16 | 17 | private readonly buildozer: Buildozer; 18 | 19 | private readonly staticLabels: Map; 20 | private readonly resolvedStaticLabelsCache: Map = new Map(); 21 | 22 | private readonly fileQueryResultCache: Map = new Map(); 23 | 24 | private listing: Readonly; 25 | 26 | constructor(private readonly flags: Flags) { 27 | this.buildozer = new Buildozer(this.flags.load_mapping); 28 | 29 | const regexLabels: Array<[string, RegExp]> = Array.from(this.flags.label_mapping.entries()) 30 | .map(pair => [pair[1], minimatch.makeRe(pair[0])]); 31 | 32 | this.staticLabels = new Map(regexLabels); 33 | 34 | if (isDebugEnabled) { 35 | debug('Rule load sites loaded:'); 36 | debug(util.inspect(this.flags.load_mapping)); 37 | lb(); 38 | debug('Static label mappings loaded:'); 39 | debug(util.inspect(this.staticLabels)); 40 | lb(); 41 | } 42 | } 43 | 44 | getFlags(): Flags { 45 | return this.flags as Flags; 46 | } 47 | 48 | getPath(): string { 49 | return this.flags.path; 50 | } 51 | 52 | getAbsolutePath() { 53 | return join(this.flags.base_dir, this.flags.path); 54 | } 55 | 56 | isDirectory(): boolean { 57 | return lstatSync(this.getAbsolutePath()).isDirectory(); 58 | } 59 | 60 | isFile(): boolean { 61 | return lstatSync(this.getAbsolutePath()).isFile(); 62 | } 63 | 64 | /** 65 | * Resolve a list of files in the path if the path represents a directory, otherwise return an empty array 66 | * The file paths are rooted at the workspace relative path 67 | */ 68 | readDirectory(): string[] { 69 | if (!this.isDirectory()) { return []; } 70 | 71 | const files = readdirSync(this.getAbsolutePath()) 72 | .map(file => this.resolveRelativeToWorkspace(file)) 73 | .filter(file => !file.endsWith(this.flags.build_file_name)); 74 | 75 | if (this.flags.pattern) { 76 | return minimatch.match(files, join(this.flags.path, this.flags.pattern)); 77 | } 78 | 79 | return files; 80 | } 81 | 82 | /** 83 | * Reads the file at path if the path represents a file, otherwise return an empty undefined 84 | */ 85 | readFileAtPath(): string { 86 | if (this.isDirectory()) { return; } 87 | return this.readFile(this.getPath()); 88 | } 89 | 90 | /** 91 | * Reads the file at the given path and returns the content as a string 92 | * @param path 93 | */ 94 | readFile(path: string): string { 95 | return readFileSync(this.resolveAbsolute(path), { encoding: 'utf-8' }); 96 | } 97 | 98 | /** 99 | * Return the parsed path info about the current path (workspace relative) 100 | */ 101 | getPathInfo(): ParsedPath { 102 | return parse(this.getPathFromBaseDir()); 103 | } 104 | 105 | /** 106 | * Returns the workspaces buildozer instance with the ability to add commands to it 107 | */ 108 | getBuildozer(): Buildozer { 109 | return this.buildozer; 110 | } 111 | 112 | /** 113 | * Returns the directory that contains the current path if path represents a file, otherwise returns path 114 | */ 115 | getPathAsDirectory(): string { 116 | return this.isFile() ? parse(this.getPathFromBaseDir()).dir : this.getPathFromBaseDir(); 117 | } 118 | 119 | /** 120 | * Returns a normalized relative path segment that is rooted at the at the workspace root 121 | * eg: 122 | * base_dir=/home/workspace/foo 123 | * path=../src/component 124 | * 125 | * = src/component 126 | */ 127 | getPathFromBaseDir(): string { 128 | return normalize(this.getPath()); 129 | } 130 | 131 | /** 132 | * Return a bazel label that represents the default target for the path 133 | */ 134 | getLabelForPath(): Label { 135 | return this.getLabelFor(this.flags.path); 136 | } 137 | 138 | /** 139 | * Returns a bazel label for the given path for the default target (eg where last package segment = target) 140 | * Optionally adding the target to the label 141 | * 142 | * If the path is a file, then the file is assumed to be part of the default label for the package. 143 | * See getLabelForFile to attempt a best guess at the file label 144 | * 145 | * All paths are considered relative to path, not the workspace root 146 | */ 147 | getLabelFor(path: string, target?: string): Label { 148 | path = this.resolveRelativeToWorkspace(path); 149 | 150 | const staticLabel = this.tryResolveLabelFromStaticMapping(path); 151 | if (staticLabel) { 152 | return staticLabel; 153 | } 154 | 155 | let label = lstatSync(this.resolveAbsolute(path)).isFile() ? parse(path).dir : path; 156 | 157 | if (target) { 158 | label = `${label}:${target}`; 159 | } 160 | 161 | return Label.parseAbsolute(`//${label}`); 162 | } 163 | 164 | /** 165 | * Returns a best guess attempt at the label for the rule that the given file is a part of. 166 | * 167 | * Allows adding an optional suffix and stripping the file extension, 168 | * note that the suffix is added after stripping the extension 169 | */ 170 | getLabelForFile(path: string, suffix?: string, stripFileExt = true): Label { 171 | path = this.resolveRelativeToWorkspace(path); 172 | 173 | const staticLabel = this.tryResolveLabelFromStaticMapping(path); 174 | if (staticLabel) { 175 | return staticLabel; 176 | } 177 | 178 | if (this.flags.use_bazel_query) { 179 | const queryLabel = this.queryForFile(path); 180 | if (queryLabel) { 181 | return queryLabel; 182 | } 183 | } 184 | 185 | const parsed = parse(path); 186 | let snake = kebabCase(stripFileExt ? parsed.name : parsed.base); 187 | 188 | if (this.flags.suffix_separator !== '-') { 189 | snake = snake.replace(/-/g, this.flags.suffix_separator); 190 | } 191 | 192 | if (suffix) { 193 | snake = `${snake}${this.flags.suffix_separator}${suffix}`; 194 | } 195 | 196 | return this.getLabelFor(parsed.dir, snake); 197 | } 198 | 199 | /** 200 | * Returns a best guess label for the given file 201 | * 202 | * Note: This does not take into account BUILD file location, so the label may cross a package boundary 203 | * 204 | * Unlike getLabelForFile, this method returns the label for the file itself, not the rule in which it resides 205 | * @param file 206 | */ 207 | getFileLabel(file: string): Label { 208 | if (this.flags.use_bazel_query) { 209 | debug(`Query for file ${file}`); 210 | 211 | const result = shell.exec( 212 | `${this.flags.bzl_binary} query ${Workspace.QUERY_FLAGS} '${file}'`, 213 | { cwd: this.getFlags().base_dir, silent: !this.flags.debug } 214 | ); 215 | 216 | if (result.code === 0) { 217 | const rule = result.stdout.trim(); 218 | if (rule.length) { 219 | return Label.parseAbsolute(rule); 220 | } 221 | } 222 | } 223 | 224 | const parsed = parse(file); 225 | return Label.parseAbsolute(`//${parsed.dir}:${parsed.base}`); 226 | } 227 | 228 | /** 229 | * Attempts to calculate the rule name for a file 230 | * 231 | * This is similar to 'getLabelForFile' but only returns the target part of the label 232 | * This can be helpful for passing as the name attr for rules 233 | */ 234 | calculateRuleName(file: string, suffix?: string, stripFileExt = true): string { 235 | return this.getLabelForFile(file, suffix, stripFileExt).getTarget(); 236 | } 237 | 238 | /** 239 | * Parses a label into its component parts 240 | */ 241 | parseLabel(label: string): Label { 242 | return Label.parseAbsolute(label); 243 | } 244 | 245 | /** 246 | * Resolves the passed path (directory or file) to a relative path rooted at the workspace (base_dir) 247 | * @param path The path to resolve 248 | */ 249 | resolveRelativeToWorkspace(path: string): string { 250 | if (this.isWorkspaceRelative(path)) { return path; } 251 | return join(this.getPathAsDirectory(), path); 252 | } 253 | 254 | /** 255 | * Determines if this path is relative to the workspace root 256 | * @param path 257 | */ 258 | isWorkspaceRelative(path: string): boolean { 259 | if (!this.listing) { 260 | this.listing = readdirSync(this.flags.base_dir); 261 | } 262 | 263 | const firstSegment = normalize(path).split(sep)[0]; 264 | return this.listing.includes(firstSegment); 265 | } 266 | 267 | /** 268 | * Returns the absolute path for the given path based on base_dir 269 | * @param path 270 | */ 271 | resolveAbsolute(path: string): string { 272 | if (isAbsolute(path)) { return path; } 273 | 274 | if (this.isWorkspaceRelative(path)) { 275 | return join(this.flags.base_dir, path); 276 | } else { 277 | return this.resolveAbsolute(this.resolveRelativeToWorkspace(path)); 278 | } 279 | } 280 | 281 | /** 282 | * Tests if the base dir is a bazel workspace 283 | * More specifically, tests that a root BUILD and WORKSPACE file exists (taking name overrides into account) 284 | * 285 | * Returns true if the both a root BUILD and WORKSPACE file exist and they are files, false if BUILD or WORKSPACE are not files 286 | * or throws if BUILD or WORKSPACE are missing 287 | */ 288 | testBaseDirSupportsBazel(): boolean { 289 | const base = this.flags.base_dir; 290 | const rootBuildFile = join(base, this.flags.build_file_name); 291 | 292 | const errorMessage = `The workspace at ${base} does not appear to be a bazel workspace.`; 293 | let hasRootBuildFile = true; 294 | try { 295 | hasRootBuildFile = lstatSync(rootBuildFile).isFile(); 296 | } catch (e) { 297 | fatal(`${errorMessage} Missing root ${this.flags.build_file_name} file`); 298 | } 299 | 300 | if (!hasRootBuildFile) { 301 | fatal(`${errorMessage} Root ${this.flags.build_file_name} file is not a file`); 302 | } 303 | 304 | const workspaceFile = join(base, 'WORKSPACE'); 305 | let hasWorkspaceFile = true; 306 | try { 307 | hasWorkspaceFile = lstatSync(workspaceFile).isFile(); 308 | } catch (e) { 309 | fatal(`${errorMessage} Missing WORKSPACE file`); 310 | } 311 | 312 | if (!hasWorkspaceFile) { 313 | fatal(`${errorMessage} WORKSPACE file is not a file`); 314 | } 315 | 316 | return hasRootBuildFile && hasWorkspaceFile; 317 | } 318 | 319 | /** 320 | * Return a path to the BUILD file in the current path 321 | */ 322 | getBuildFilePath(): string { 323 | return this.isDirectory() ? 324 | join(this.getAbsolutePath(), this.flags.build_file_name) : 325 | join(this.getAbsolutePath(), '..', this.flags.build_file_name); 326 | } 327 | 328 | /** 329 | * Checks if a BUILD file exists at path and that it is a file 330 | */ 331 | hasBuildFileAtPath(): boolean { 332 | const buildFilePath = this.getBuildFilePath(); 333 | 334 | try { 335 | return lstatSync(buildFilePath).isFile(); 336 | } catch (e) { 337 | return false; 338 | } 339 | } 340 | 341 | /** 342 | * Returns the label for an import where a static mapping exists, 343 | * otherwise returns undefined. 344 | */ 345 | tryResolveLabelFromStaticMapping(imp: string, defaultValue?: string, relativePrefix?: string): Label | undefined { 346 | // convert to a workspace relative path, this call is a noop if the path is already workspace relative 347 | if (relativePrefix && imp.startsWith(relativePrefix)) { 348 | imp = this.resolveRelativeToWorkspace(imp); 349 | } 350 | 351 | if (this.resolvedStaticLabelsCache.has(imp)) { 352 | return this.resolvedStaticLabelsCache.get(imp); 353 | } 354 | 355 | // find returns the first found truthy match, so there _may_ be a more specific glob in the map 356 | // but we won't find it - room for improvement, but the consumer can move them up the list 357 | const result = Array.from(this.staticLabels.entries()) 358 | .find(([_, value]) => !!value.exec(imp)); 359 | 360 | if (!result) { 361 | return defaultValue ? Label.parseAbsolute(defaultValue) : undefined; 362 | } 363 | 364 | const staticMapped = result[0]; 365 | const label = Label.parseAbsolute(staticMapped); 366 | 367 | this.resolvedStaticLabelsCache.set(imp, label); 368 | 369 | return label; 370 | } 371 | 372 | /** 373 | * Invokes a buildozer class in the base directory 374 | */ 375 | invokeBuildozer() { 376 | if (!this.flags.generate_build_files && !this.flags.output_buildozer_to_console) { 377 | log(`--no-generate_build_files set, not generating ${this.flags.build_file_name} files`); 378 | return; 379 | } 380 | 381 | if (this.flags.output_buildozer_to_console) { 382 | log('\n' + this.buildozer.toCommands()); 383 | return; 384 | } 385 | 386 | const commands = this.buildozer.toCommandBatch(); 387 | if (!commands.length) { 388 | warn('No buildozer commands were generated'); 389 | return; 390 | } 391 | 392 | const hasBuildFileAtPath = this.hasBuildFileAtPath(); 393 | if (hasBuildFileAtPath && this.flags.nuke_build_file) { 394 | shell.rm(this.getBuildFilePath()); 395 | shell.touch(this.getBuildFilePath()); 396 | } else if (!hasBuildFileAtPath) { 397 | shell.touch(this.getBuildFilePath()); 398 | } 399 | 400 | debug('Invoking buildozer'); 401 | 402 | try { 403 | BazelBuildozer.runWithOptions(commands, { cwd: this.flags.base_dir }, ['-shorten_labels', '-eol-comments=true', '-k']); 404 | log(`Generated ${this.flags.build_file_name} files`); 405 | } catch (e) { 406 | fatal(`Error generating ${this.flags.build_file_name} files`); 407 | } 408 | } 409 | 410 | private queryForFile(file: string): Label { 411 | if (this.fileQueryResultCache.has(file)) { 412 | return this.fileQueryResultCache.get(file); 413 | } 414 | 415 | const parts = file.split('/'); 416 | const name = parts.pop(); 417 | 418 | const label = `//${parts.join('/')}:${name}`; 419 | 420 | debug(`Query for containing rule with for file ${file}`); 421 | 422 | const term = `"attr('src', ${label}, //...)"`; 423 | const term2 = `"attr('srcs', ${label}, //...)"`; 424 | 425 | const result = shell.exec( 426 | `${this.flags.bazel_binary} query ${Workspace.QUERY_FLAGS} ${term} + ${term2}`, 427 | { cwd: this.getFlags().base_dir, silent: !this.flags.debug } 428 | ); 429 | 430 | if (result.code === 0) { 431 | const rule = result.stdout.trim(); 432 | 433 | if (rule.length) { 434 | const label = Label.parseAbsolute(rule); 435 | this.fileQueryResultCache.set(file, label); 436 | 437 | return label; 438 | } 439 | } 440 | } 441 | 442 | } 443 | -------------------------------------------------------------------------------- /yarn.lock: -------------------------------------------------------------------------------- 1 | # THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. 2 | # yarn lockfile v1 3 | 4 | 5 | "@bazel/buildozer@3.4.0": 6 | version "3.4.0" 7 | resolved "https://registry.yarnpkg.com/@bazel/buildozer/-/buildozer-3.4.0.tgz#3c728842fc8f57a0274b8cbe4c489644f23e6568" 8 | integrity sha512-juvMR1uiWkh9Ud4D2ecgU72ZcOlvMIWprxb4W6L7phTCP2CQCadrFrWTYvYx8fhtt4z62i6SYBLyL68L6GOWGg== 9 | 10 | "@bazel/jasmine@2.0.2": 11 | version "2.0.2" 12 | resolved "https://registry.yarnpkg.com/@bazel/jasmine/-/jasmine-2.0.2.tgz#a4ccd3bf0b780d3d617cee07d146d459076385e4" 13 | integrity sha512-tmQY124GSTJFN67zIjTn34YAUUaPqBcC9MnDhYPyZDWqdbJ5SqDQ4aNQpRDmZvnOV3c14dKKHpXZy28nyFovOA== 14 | dependencies: 15 | c8 "~7.1.0" 16 | jasmine-reporters "~2.3.2" 17 | 18 | "@bazel/typescript@2.0.2": 19 | version "2.0.2" 20 | resolved "https://registry.yarnpkg.com/@bazel/typescript/-/typescript-2.0.2.tgz#02a2b81e5b73224eace8cec4735a2b0f9975f199" 21 | integrity sha512-Ygv3HVxa/y9qnazi8hPvGwXsooeZ2RhgQCJtcIV7QLyGb+X8gv5ZUPlSKkXVI94TFO2x6pxFQHHcgKOEu4HWaw== 22 | dependencies: 23 | protobufjs "6.8.8" 24 | semver "5.6.0" 25 | source-map-support "0.5.9" 26 | tsutils "2.27.2" 27 | 28 | "@bcoe/v8-coverage@^0.2.3": 29 | version "0.2.3" 30 | resolved "https://registry.yarnpkg.com/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz#75a2e8b51cb758a7553d6804a5932d7aace75c39" 31 | integrity sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw== 32 | 33 | "@istanbuljs/schema@^0.1.2": 34 | version "0.1.2" 35 | resolved "https://registry.yarnpkg.com/@istanbuljs/schema/-/schema-0.1.2.tgz#26520bf09abe4a5644cd5414e37125a8954241dd" 36 | integrity sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw== 37 | 38 | "@mrmlnc/readdir-enhanced@^2.2.1": 39 | version "2.2.1" 40 | resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" 41 | integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== 42 | dependencies: 43 | call-me-maybe "^1.0.1" 44 | glob-to-regexp "^0.3.0" 45 | 46 | "@nodelib/fs.stat@^1.1.2": 47 | version "1.1.3" 48 | resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" 49 | integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== 50 | 51 | "@phenomnomnominal/tsquery@4.1.0": 52 | version "4.1.0" 53 | resolved "https://registry.yarnpkg.com/@phenomnomnominal/tsquery/-/tsquery-4.1.0.tgz#9c836d6db829b5127ccc1ffd8e4c2ad08d600071" 54 | integrity sha512-+i1eqUJODVanUDuTdOPgnjErFg21DKGLstdRXp4LLGcSbO7c+3pwJPkmdSfbkh9gO6xaHJ/5ftSAMqEFJF5cGA== 55 | dependencies: 56 | esquery "^1.0.1" 57 | 58 | "@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": 59 | version "1.1.2" 60 | resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" 61 | integrity sha1-m4sMxmPWaafY9vXQiToU00jzD78= 62 | 63 | "@protobufjs/base64@^1.1.2": 64 | version "1.1.2" 65 | resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" 66 | integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== 67 | 68 | "@protobufjs/codegen@^2.0.4": 69 | version "2.0.4" 70 | resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" 71 | integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== 72 | 73 | "@protobufjs/eventemitter@^1.1.0": 74 | version "1.1.0" 75 | resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" 76 | integrity sha1-NVy8mLr61ZePntCV85diHx0Ga3A= 77 | 78 | "@protobufjs/fetch@^1.1.0": 79 | version "1.1.0" 80 | resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" 81 | integrity sha1-upn7WYYUr2VwDBYZ/wbUVLDYTEU= 82 | dependencies: 83 | "@protobufjs/aspromise" "^1.1.1" 84 | "@protobufjs/inquire" "^1.1.0" 85 | 86 | "@protobufjs/float@^1.0.2": 87 | version "1.0.2" 88 | resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" 89 | integrity sha1-Xp4avctz/Ap8uLKR33jIy9l7h9E= 90 | 91 | "@protobufjs/inquire@^1.1.0": 92 | version "1.1.0" 93 | resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" 94 | integrity sha1-/yAOPnzyQp4tyvwRQIKOjMY48Ik= 95 | 96 | "@protobufjs/path@^1.1.2": 97 | version "1.1.2" 98 | resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" 99 | integrity sha1-bMKyDFya1q0NzP0hynZz2Nf79o0= 100 | 101 | "@protobufjs/pool@^1.1.0": 102 | version "1.1.0" 103 | resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" 104 | integrity sha1-Cf0V8tbTq/qbZbw2ZQbWrXhG/1Q= 105 | 106 | "@protobufjs/utf8@^1.1.0": 107 | version "1.1.0" 108 | resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" 109 | integrity sha1-p3c2C1s5oaLlEG+OhY8v0tBgxXA= 110 | 111 | "@types/color-name@^1.1.1": 112 | version "1.1.1" 113 | resolved "https://registry.yarnpkg.com/@types/color-name/-/color-name-1.1.1.tgz#1c1261bbeaa10a8055bbc5d8ab84b7b2afc846a0" 114 | integrity sha512-rr+OQyAjxze7GgWrSaJwydHStIhHq2lvY3BOC2Mj7KnzI7XK0Uw1TOOdI9lDoajEbSWLiYgoo4f1R51erQfhPQ== 115 | 116 | "@types/events@*": 117 | version "3.0.0" 118 | resolved "https://registry.yarnpkg.com/@types/events/-/events-3.0.0.tgz#2862f3f58a9a7f7c3e78d79f130dd4d71c25c2a7" 119 | integrity sha512-EaObqwIvayI5a8dCzhFrjKzVwKLxjoG9T6Ppd5CEo07LRKfQ8Yokw54r5+Wq7FaBQ+yXRvQAYPrHwya1/UFt9g== 120 | 121 | "@types/glob@*": 122 | version "7.1.1" 123 | resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.1.1.tgz#aa59a1c6e3fbc421e07ccd31a944c30eba521575" 124 | integrity sha512-1Bh06cbWJUHMC97acuD6UMG29nMt0Aqz1vF3guLfG+kHHJhy3AyohZFFxYk2f7Q1SQIrNwvncxAE0N/9s70F2w== 125 | dependencies: 126 | "@types/events" "*" 127 | "@types/minimatch" "*" 128 | "@types/node" "*" 129 | 130 | "@types/is-windows@^1.0.0": 131 | version "1.0.0" 132 | resolved "https://registry.yarnpkg.com/@types/is-windows/-/is-windows-1.0.0.tgz#1011fa129d87091e2f6faf9042d6704cdf2e7be0" 133 | integrity sha512-tJ1rq04tGKuIJoWIH0Gyuwv4RQ3+tIu7wQrC0MV47raQ44kIzXSSFKfrxFUOWVRvesoF7mrTqigXmqoZJsXwTg== 134 | 135 | "@types/istanbul-lib-coverage@^2.0.1": 136 | version "2.0.3" 137 | resolved "https://registry.yarnpkg.com/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.3.tgz#4ba8ddb720221f432e443bd5f9117fd22cfd4762" 138 | integrity sha512-sz7iLqvVUg1gIedBOvlkxPlc8/uVzyS5OwGz1cKjXzkl3FpL3al0crU8YGU1WoHkxn0Wxbw5tyi6hvzJKNzFsw== 139 | 140 | "@types/jasmine@3.5.12": 141 | version "3.5.12" 142 | resolved "https://registry.yarnpkg.com/@types/jasmine/-/jasmine-3.5.12.tgz#5c378c1545cdc7cb339cff5578f854b6d1e0a17d" 143 | integrity sha512-vJaQ58oceFao+NzpKNqLOWwHPsqA7YEhKv+mOXvYU4/qh+BfVWIxaBtL0Ck5iCS67yOkNwGkDCrzepnzIWF+7g== 144 | 145 | "@types/json5@^0.0.29": 146 | version "0.0.29" 147 | resolved "https://registry.yarnpkg.com/@types/json5/-/json5-0.0.29.tgz#ee28707ae94e11d2b827bcbe5270bcea7f3e71ee" 148 | integrity sha1-7ihweulOEdK4J7y+UnC86n8+ce4= 149 | 150 | "@types/long@^4.0.0": 151 | version "4.0.1" 152 | resolved "https://registry.yarnpkg.com/@types/long/-/long-4.0.1.tgz#459c65fa1867dafe6a8f322c4c51695663cc55e9" 153 | integrity sha512-5tXH6Bx/kNGd3MgffdmP4dy2Z+G4eaXw0SE81Tq3BNadtnMR5/ySMzX4SLEzHJzSmPNn4HIdpQsBvXMUykr58w== 154 | 155 | "@types/minimatch@*", "@types/minimatch@3.0.3": 156 | version "3.0.3" 157 | resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d" 158 | integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA== 159 | 160 | "@types/mock-fs@4.10.0": 161 | version "4.10.0" 162 | resolved "https://registry.yarnpkg.com/@types/mock-fs/-/mock-fs-4.10.0.tgz#460061b186993d76856f669d5317cda8a007c24b" 163 | integrity sha512-FQ5alSzmHMmliqcL36JqIA4Yyn9jyJKvRSGV3mvPh108VFatX7naJDzSG4fnFQNZFq9dIx0Dzoe6ddflMB2Xkg== 164 | dependencies: 165 | "@types/node" "*" 166 | 167 | "@types/node@*": 168 | version "13.13.2" 169 | resolved "https://registry.yarnpkg.com/@types/node/-/node-13.13.2.tgz#160d82623610db590a64e8ca81784e11117e5a54" 170 | integrity sha512-LB2R1Oyhpg8gu4SON/mfforE525+Hi/M1ineICEDftqNVTyFg1aRIeGuTvXAoWHc4nbrFncWtJgMmoyRvuGh7A== 171 | 172 | "@types/node@14.0.27": 173 | version "14.0.27" 174 | resolved "https://registry.yarnpkg.com/@types/node/-/node-14.0.27.tgz#a151873af5a5e851b51b3b065c9e63390a9e0eb1" 175 | integrity sha512-kVrqXhbclHNHGu9ztnAwSncIgJv/FaxmzXJvGXNdcCpV1b8u1/Mi6z6m0vwy0LzKeXFTPLH0NzwmoJ3fNCIq0g== 176 | 177 | "@types/node@^10.1.0": 178 | version "10.17.21" 179 | resolved "https://registry.yarnpkg.com/@types/node/-/node-10.17.21.tgz#c00e9603399126925806bed2d9a1e37da506965e" 180 | integrity sha512-PQKsydPxYxF1DsAFWmunaxd3sOi3iMt6Zmx/tgaagHYmwJ/9cRH91hQkeJZaUGWbvn0K5HlSVEXkn5U/llWPpQ== 181 | 182 | "@types/shelljs@0.8.8": 183 | version "0.8.8" 184 | resolved "https://registry.yarnpkg.com/@types/shelljs/-/shelljs-0.8.8.tgz#e439c69929b88a2c8123c1a55e09eb708315addf" 185 | integrity sha512-lD3LWdg6j8r0VRBFahJVaxoW0SIcswxKaFUrmKl33RJVeeoNYQAz4uqCJ5Z6v4oIBOsC5GozX+I5SorIKiTcQA== 186 | dependencies: 187 | "@types/glob" "*" 188 | "@types/node" "*" 189 | 190 | "@types/yargs-parser@*": 191 | version "15.0.0" 192 | resolved "https://registry.yarnpkg.com/@types/yargs-parser/-/yargs-parser-15.0.0.tgz#cb3f9f741869e20cce330ffbeb9271590483882d" 193 | integrity sha512-FA/BWv8t8ZWJ+gEOnLLd8ygxH/2UFbAvgEonyfN6yWGLKc7zVjbpl2Y4CTjid9h2RfgPP6SEt6uHwEOply00yw== 194 | 195 | "@types/yargs@15.0.9": 196 | version "15.0.9" 197 | resolved "https://registry.yarnpkg.com/@types/yargs/-/yargs-15.0.9.tgz#524cd7998fe810cdb02f26101b699cccd156ff19" 198 | integrity sha512-HmU8SeIRhZCWcnRskCs36Q1Q00KBV6Cqh/ora8WN1+22dY07AZdn6Gel8QZ3t26XYPImtcL8WV/eqjhVmMEw4g== 199 | dependencies: 200 | "@types/yargs-parser" "*" 201 | 202 | "@yarnpkg/lockfile@^1.1.0": 203 | version "1.1.0" 204 | resolved "https://registry.yarnpkg.com/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz#e77a97fbd345b76d83245edcd17d393b1b41fb31" 205 | integrity sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ== 206 | 207 | ansi-regex@^5.0.0: 208 | version "5.0.0" 209 | resolved "https://registry.yarnpkg.com/ansi-regex/-/ansi-regex-5.0.0.tgz#388539f55179bf39339c81af30a654d69f87cb75" 210 | integrity sha512-bY6fj56OUQ0hU1KjFNDQuJFezqKdrAyFdIevADiqrWHwSlbmBNMHp5ak2f40Pm8JTFyM2mqxkG6ngkHO11f/lg== 211 | 212 | ansi-styles@^3.2.1: 213 | version "3.2.1" 214 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" 215 | integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== 216 | dependencies: 217 | color-convert "^1.9.0" 218 | 219 | ansi-styles@^4.0.0: 220 | version "4.2.1" 221 | resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-4.2.1.tgz#90ae75c424d008d2624c5bf29ead3177ebfcf359" 222 | integrity sha512-9VGjrMsG1vePxcSweQsN20KY/c4zN0h9fLjqAbwbPfahM3t+NL+M9HC8xeXG2I8pX5NoamTGNuomEUFI7fcUjA== 223 | dependencies: 224 | "@types/color-name" "^1.1.1" 225 | color-convert "^2.0.1" 226 | 227 | arr-diff@^4.0.0: 228 | version "4.0.0" 229 | resolved "https://registry.yarnpkg.com/arr-diff/-/arr-diff-4.0.0.tgz#d6461074febfec71e7e15235761a329a5dc7c520" 230 | integrity sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA= 231 | 232 | arr-flatten@^1.1.0: 233 | version "1.1.0" 234 | resolved "https://registry.yarnpkg.com/arr-flatten/-/arr-flatten-1.1.0.tgz#36048bbff4e7b47e136644316c99669ea5ae91f1" 235 | integrity sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg== 236 | 237 | arr-union@^3.1.0: 238 | version "3.1.0" 239 | resolved "https://registry.yarnpkg.com/arr-union/-/arr-union-3.1.0.tgz#e39b09aea9def866a8f206e288af63919bae39c4" 240 | integrity sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ= 241 | 242 | array-unique@^0.3.2: 243 | version "0.3.2" 244 | resolved "https://registry.yarnpkg.com/array-unique/-/array-unique-0.3.2.tgz#a894b75d4bc4f6cd679ef3244a9fd8f46ae2d428" 245 | integrity sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg= 246 | 247 | assign-symbols@^1.0.0: 248 | version "1.0.0" 249 | resolved "https://registry.yarnpkg.com/assign-symbols/-/assign-symbols-1.0.0.tgz#59667f41fadd4f20ccbc2bb96b8d4f7f78ec0367" 250 | integrity sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c= 251 | 252 | atob@^2.1.2: 253 | version "2.1.2" 254 | resolved "https://registry.yarnpkg.com/atob/-/atob-2.1.2.tgz#6d9517eb9e030d2436666651e86bd9f6f13533c9" 255 | integrity sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg== 256 | 257 | balanced-match@^1.0.0: 258 | version "1.0.0" 259 | resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" 260 | integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= 261 | 262 | base@^0.11.1: 263 | version "0.11.2" 264 | resolved "https://registry.yarnpkg.com/base/-/base-0.11.2.tgz#7bde5ced145b6d551a90db87f83c558b4eb48a8f" 265 | integrity sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg== 266 | dependencies: 267 | cache-base "^1.0.1" 268 | class-utils "^0.3.5" 269 | component-emitter "^1.2.1" 270 | define-property "^1.0.0" 271 | isobject "^3.0.1" 272 | mixin-deep "^1.2.0" 273 | pascalcase "^0.1.1" 274 | 275 | brace-expansion@^1.1.7: 276 | version "1.1.11" 277 | resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" 278 | integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== 279 | dependencies: 280 | balanced-match "^1.0.0" 281 | concat-map "0.0.1" 282 | 283 | braces@^2.3.1: 284 | version "2.3.2" 285 | resolved "https://registry.yarnpkg.com/braces/-/braces-2.3.2.tgz#5979fd3f14cd531565e5fa2df1abfff1dfaee729" 286 | integrity sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w== 287 | dependencies: 288 | arr-flatten "^1.1.0" 289 | array-unique "^0.3.2" 290 | extend-shallow "^2.0.1" 291 | fill-range "^4.0.0" 292 | isobject "^3.0.1" 293 | repeat-element "^1.1.2" 294 | snapdragon "^0.8.1" 295 | snapdragon-node "^2.0.1" 296 | split-string "^3.0.2" 297 | to-regex "^3.0.1" 298 | 299 | buffer-from@^1.0.0: 300 | version "1.1.1" 301 | resolved "https://registry.yarnpkg.com/buffer-from/-/buffer-from-1.1.1.tgz#32713bc028f75c02fdb710d7c7bcec1f2c6070ef" 302 | integrity sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A== 303 | 304 | builtins@3.0.1: 305 | version "3.0.1" 306 | resolved "https://registry.yarnpkg.com/builtins/-/builtins-3.0.1.tgz#38c55022f40a752f61de255eabd41892278032ea" 307 | integrity sha512-JxlnRUmQpQReAt5mUshMNQpHe7MEZuy1qH+Eck31mc4GBBM9AmGX9oBrzQH/zAOIRM/CAqNA0J2692a/yJiGQQ== 308 | dependencies: 309 | semver "^7.0.0" 310 | 311 | c8@~7.1.0: 312 | version "7.1.2" 313 | resolved "https://registry.yarnpkg.com/c8/-/c8-7.1.2.tgz#3fd785e8d264175ceffe92c74607f5cfb12f018d" 314 | integrity sha512-lCEwL9lbvWOQLxoLw8RF7PM8Cdj+rKxRp/PyWC9S8xASvYHRwXQ2gxzsNTgLhQM1Utc1YDAjzQYPQIxVEyelGg== 315 | dependencies: 316 | "@bcoe/v8-coverage" "^0.2.3" 317 | "@istanbuljs/schema" "^0.1.2" 318 | find-up "^4.0.0" 319 | foreground-child "^2.0.0" 320 | furi "^2.0.0" 321 | istanbul-lib-coverage "^3.0.0" 322 | istanbul-lib-report "^3.0.0" 323 | istanbul-reports "^3.0.2" 324 | rimraf "^3.0.0" 325 | test-exclude "^6.0.0" 326 | v8-to-istanbul "^4.1.2" 327 | yargs "^15.0.0" 328 | yargs-parser "^18.0.0" 329 | 330 | cache-base@^1.0.1: 331 | version "1.0.1" 332 | resolved "https://registry.yarnpkg.com/cache-base/-/cache-base-1.0.1.tgz#0a7f46416831c8b662ee36fe4e7c59d76f666ab2" 333 | integrity sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ== 334 | dependencies: 335 | collection-visit "^1.0.0" 336 | component-emitter "^1.2.1" 337 | get-value "^2.0.6" 338 | has-value "^1.0.0" 339 | isobject "^3.0.1" 340 | set-value "^2.0.0" 341 | to-object-path "^0.3.0" 342 | union-value "^1.0.0" 343 | unset-value "^1.0.0" 344 | 345 | call-me-maybe@^1.0.1: 346 | version "1.0.1" 347 | resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b" 348 | integrity sha1-JtII6onje1y95gJQoV8DHBak1ms= 349 | 350 | camelcase@^5.0.0: 351 | version "5.3.1" 352 | resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320" 353 | integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg== 354 | 355 | chalk@^2.3.2, chalk@^2.4.2: 356 | version "2.4.2" 357 | resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" 358 | integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== 359 | dependencies: 360 | ansi-styles "^3.2.1" 361 | escape-string-regexp "^1.0.5" 362 | supports-color "^5.3.0" 363 | 364 | ci-info@^2.0.0: 365 | version "2.0.0" 366 | resolved "https://registry.yarnpkg.com/ci-info/-/ci-info-2.0.0.tgz#67a9e964be31a51e15e5010d58e6f12834002f46" 367 | integrity sha512-5tK7EtrZ0N+OLFMthtqOj4fI2Jeb88C4CAZPu25LDVUgXJ0A3Js4PMGqrn0JU1W0Mh1/Z8wZzYPxqUrXeBboCQ== 368 | 369 | class-utils@^0.3.5: 370 | version "0.3.6" 371 | resolved "https://registry.yarnpkg.com/class-utils/-/class-utils-0.3.6.tgz#f93369ae8b9a7ce02fd41faad0ca83033190c463" 372 | integrity sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg== 373 | dependencies: 374 | arr-union "^3.1.0" 375 | define-property "^0.2.5" 376 | isobject "^3.0.0" 377 | static-extend "^0.1.1" 378 | 379 | cliui@^6.0.0: 380 | version "6.0.0" 381 | resolved "https://registry.yarnpkg.com/cliui/-/cliui-6.0.0.tgz#511d702c0c4e41ca156d7d0e96021f23e13225b1" 382 | integrity sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ== 383 | dependencies: 384 | string-width "^4.2.0" 385 | strip-ansi "^6.0.0" 386 | wrap-ansi "^6.2.0" 387 | 388 | collection-visit@^1.0.0: 389 | version "1.0.0" 390 | resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0" 391 | integrity sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA= 392 | dependencies: 393 | map-visit "^1.0.0" 394 | object-visit "^1.0.0" 395 | 396 | color-convert@^1.9.0: 397 | version "1.9.3" 398 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" 399 | integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== 400 | dependencies: 401 | color-name "1.1.3" 402 | 403 | color-convert@^2.0.1: 404 | version "2.0.1" 405 | resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-2.0.1.tgz#72d3a68d598c9bdb3af2ad1e84f21d896abd4de3" 406 | integrity sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ== 407 | dependencies: 408 | color-name "~1.1.4" 409 | 410 | color-name@1.1.3: 411 | version "1.1.3" 412 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" 413 | integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= 414 | 415 | color-name@~1.1.4: 416 | version "1.1.4" 417 | resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.4.tgz#c2a09a87acbde69543de6f63fa3995c826c536a2" 418 | integrity sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA== 419 | 420 | component-emitter@^1.2.1: 421 | version "1.3.0" 422 | resolved "https://registry.yarnpkg.com/component-emitter/-/component-emitter-1.3.0.tgz#16e4070fba8ae29b679f2215853ee181ab2eabc0" 423 | integrity sha512-Rd3se6QB+sO1TwqZjscQrurpEPIfO0/yYnSin6Q/rD3mOutHvUrCAhJub3r90uNb+SESBuE0QYoB90YdfatsRg== 424 | 425 | concat-map@0.0.1: 426 | version "0.0.1" 427 | resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" 428 | integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= 429 | 430 | convert-source-map@^1.6.0: 431 | version "1.7.0" 432 | resolved "https://registry.yarnpkg.com/convert-source-map/-/convert-source-map-1.7.0.tgz#17a2cb882d7f77d3490585e2ce6c524424a3a442" 433 | integrity sha512-4FJkXzKXEDB1snCFZlLP4gpC3JILicCpGbzG9f9G7tGqGCzETQ2hWPrcinA9oU4wtf2biUaEH5065UnMeR33oA== 434 | dependencies: 435 | safe-buffer "~5.1.1" 436 | 437 | copy-descriptor@^0.1.0: 438 | version "0.1.1" 439 | resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d" 440 | integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40= 441 | 442 | cross-spawn@^6.0.5: 443 | version "6.0.5" 444 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-6.0.5.tgz#4a5ec7c64dfae22c3a14124dbacdee846d80cbc4" 445 | integrity sha512-eTVLrBSt7fjbDygz805pMnstIs2VTBNkRm0qxZd+M7A5XDdxVRWO5MxGBXZhjY4cqLYLdtrGqRf8mBPmzwSpWQ== 446 | dependencies: 447 | nice-try "^1.0.4" 448 | path-key "^2.0.1" 449 | semver "^5.5.0" 450 | shebang-command "^1.2.0" 451 | which "^1.2.9" 452 | 453 | cross-spawn@^7.0.0: 454 | version "7.0.3" 455 | resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" 456 | integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w== 457 | dependencies: 458 | path-key "^3.1.0" 459 | shebang-command "^2.0.0" 460 | which "^2.0.1" 461 | 462 | debug@^2.2.0, debug@^2.3.3: 463 | version "2.6.9" 464 | resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" 465 | integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== 466 | dependencies: 467 | ms "2.0.0" 468 | 469 | decamelize@^1.2.0: 470 | version "1.2.0" 471 | resolved "https://registry.yarnpkg.com/decamelize/-/decamelize-1.2.0.tgz#f6534d15148269b20352e7bee26f501f9a191290" 472 | integrity sha1-9lNNFRSCabIDUue+4m9QH5oZEpA= 473 | 474 | decode-uri-component@^0.2.0: 475 | version "0.2.0" 476 | resolved "https://registry.yarnpkg.com/decode-uri-component/-/decode-uri-component-0.2.0.tgz#eb3913333458775cb84cd1a1fae062106bb87545" 477 | integrity sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU= 478 | 479 | define-property@^0.2.5: 480 | version "0.2.5" 481 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-0.2.5.tgz#c35b1ef918ec3c990f9a5bc57be04aacec5c8116" 482 | integrity sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY= 483 | dependencies: 484 | is-descriptor "^0.1.0" 485 | 486 | define-property@^1.0.0: 487 | version "1.0.0" 488 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-1.0.0.tgz#769ebaaf3f4a63aad3af9e8d304c9bbe79bfb0e6" 489 | integrity sha1-dp66rz9KY6rTr56NMEybvnm/sOY= 490 | dependencies: 491 | is-descriptor "^1.0.0" 492 | 493 | define-property@^2.0.2: 494 | version "2.0.2" 495 | resolved "https://registry.yarnpkg.com/define-property/-/define-property-2.0.2.tgz#d459689e8d654ba77e02a817f8710d702cb16e9d" 496 | integrity sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ== 497 | dependencies: 498 | is-descriptor "^1.0.2" 499 | isobject "^3.0.1" 500 | 501 | emoji-regex@^8.0.0: 502 | version "8.0.0" 503 | resolved "https://registry.yarnpkg.com/emoji-regex/-/emoji-regex-8.0.0.tgz#e818fd69ce5ccfcb404594f842963bf53164cc37" 504 | integrity sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A== 505 | 506 | error-ex@^1.3.1: 507 | version "1.3.2" 508 | resolved "https://registry.yarnpkg.com/error-ex/-/error-ex-1.3.2.tgz#b4ac40648107fdcdcfae242f428bea8a14d4f1bf" 509 | integrity sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g== 510 | dependencies: 511 | is-arrayish "^0.2.1" 512 | 513 | escape-string-regexp@^1.0.5: 514 | version "1.0.5" 515 | resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" 516 | integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= 517 | 518 | esquery@^1.0.1: 519 | version "1.3.1" 520 | resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.3.1.tgz#b78b5828aa8e214e29fb74c4d5b752e1c033da57" 521 | integrity sha512-olpvt9QG0vniUBZspVRN6lwB7hOZoTRtT+jzR+tS4ffYx2mzbw+z0XCOk44aaLYKApNX5nMm+E+P6o25ip/DHQ== 522 | dependencies: 523 | estraverse "^5.1.0" 524 | 525 | estraverse@^5.1.0: 526 | version "5.1.0" 527 | resolved "https://registry.yarnpkg.com/estraverse/-/estraverse-5.1.0.tgz#374309d39fd935ae500e7b92e8a6b4c720e59642" 528 | integrity sha512-FyohXK+R0vE+y1nHLoBM7ZTyqRpqAlhdZHCWIWEviFLiGB8b04H6bQs8G+XTthacvT8VuwvteiP7RJSxMs8UEw== 529 | 530 | expand-brackets@^2.1.4: 531 | version "2.1.4" 532 | resolved "https://registry.yarnpkg.com/expand-brackets/-/expand-brackets-2.1.4.tgz#b77735e315ce30f6b6eff0f83b04151a22449622" 533 | integrity sha1-t3c14xXOMPa27/D4OwQVGiJEliI= 534 | dependencies: 535 | debug "^2.3.3" 536 | define-property "^0.2.5" 537 | extend-shallow "^2.0.1" 538 | posix-character-classes "^0.1.0" 539 | regex-not "^1.0.0" 540 | snapdragon "^0.8.1" 541 | to-regex "^3.0.1" 542 | 543 | extend-shallow@^2.0.1: 544 | version "2.0.1" 545 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-2.0.1.tgz#51af7d614ad9a9f610ea1bafbb989d6b1c56890f" 546 | integrity sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8= 547 | dependencies: 548 | is-extendable "^0.1.0" 549 | 550 | extend-shallow@^3.0.0, extend-shallow@^3.0.2: 551 | version "3.0.2" 552 | resolved "https://registry.yarnpkg.com/extend-shallow/-/extend-shallow-3.0.2.tgz#26a71aaf073b39fb2127172746131c2704028db8" 553 | integrity sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg= 554 | dependencies: 555 | assign-symbols "^1.0.0" 556 | is-extendable "^1.0.1" 557 | 558 | extglob@^2.0.4: 559 | version "2.0.4" 560 | resolved "https://registry.yarnpkg.com/extglob/-/extglob-2.0.4.tgz#ad00fe4dc612a9232e8718711dc5cb5ab0285543" 561 | integrity sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw== 562 | dependencies: 563 | array-unique "^0.3.2" 564 | define-property "^1.0.0" 565 | expand-brackets "^2.1.4" 566 | extend-shallow "^2.0.1" 567 | fragment-cache "^0.2.1" 568 | regex-not "^1.0.0" 569 | snapdragon "^0.8.1" 570 | to-regex "^3.0.1" 571 | 572 | fast-glob@^2.2.6: 573 | version "2.2.7" 574 | resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" 575 | integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== 576 | dependencies: 577 | "@mrmlnc/readdir-enhanced" "^2.2.1" 578 | "@nodelib/fs.stat" "^1.1.2" 579 | glob-parent "^3.1.0" 580 | is-glob "^4.0.0" 581 | merge2 "^1.2.3" 582 | micromatch "^3.1.10" 583 | 584 | figures@^2.0.0: 585 | version "2.0.0" 586 | resolved "https://registry.yarnpkg.com/figures/-/figures-2.0.0.tgz#3ab1a2d2a62c8bfb431a0c94cb797a2fce27c962" 587 | integrity sha1-OrGi0qYsi/tDGgyUy3l6L84nyWI= 588 | dependencies: 589 | escape-string-regexp "^1.0.5" 590 | 591 | fill-range@^4.0.0: 592 | version "4.0.0" 593 | resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-4.0.0.tgz#d544811d428f98eb06a63dc402d2403c328c38f7" 594 | integrity sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc= 595 | dependencies: 596 | extend-shallow "^2.0.1" 597 | is-number "^3.0.0" 598 | repeat-string "^1.6.1" 599 | to-regex-range "^2.1.0" 600 | 601 | find-up@^2.0.0: 602 | version "2.1.0" 603 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7" 604 | integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c= 605 | dependencies: 606 | locate-path "^2.0.0" 607 | 608 | find-up@^4.0.0, find-up@^4.1.0: 609 | version "4.1.0" 610 | resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19" 611 | integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw== 612 | dependencies: 613 | locate-path "^5.0.0" 614 | path-exists "^4.0.0" 615 | 616 | find-yarn-workspace-root@^1.2.1: 617 | version "1.2.1" 618 | resolved "https://registry.yarnpkg.com/find-yarn-workspace-root/-/find-yarn-workspace-root-1.2.1.tgz#40eb8e6e7c2502ddfaa2577c176f221422f860db" 619 | integrity sha512-dVtfb0WuQG+8Ag2uWkbG79hOUzEsRrhBzgfn86g2sJPkzmcpGdghbNTfUKGTxymFrY/tLIodDzLoW9nOJ4FY8Q== 620 | dependencies: 621 | fs-extra "^4.0.3" 622 | micromatch "^3.1.4" 623 | 624 | for-in@^1.0.2: 625 | version "1.0.2" 626 | resolved "https://registry.yarnpkg.com/for-in/-/for-in-1.0.2.tgz#81068d295a8142ec0ac726c6e2200c30fb6d5e80" 627 | integrity sha1-gQaNKVqBQuwKxybG4iAMMPttXoA= 628 | 629 | foreground-child@^2.0.0: 630 | version "2.0.0" 631 | resolved "https://registry.yarnpkg.com/foreground-child/-/foreground-child-2.0.0.tgz#71b32800c9f15aa8f2f83f4a6bd9bff35d861a53" 632 | integrity sha512-dCIq9FpEcyQyXKCkyzmlPTFNgrCzPudOe+mhvJU5zAtlBnGVy2yKxtfsxK2tQBThwq225jcvBjpw1Gr40uzZCA== 633 | dependencies: 634 | cross-spawn "^7.0.0" 635 | signal-exit "^3.0.2" 636 | 637 | fragment-cache@^0.2.1: 638 | version "0.2.1" 639 | resolved "https://registry.yarnpkg.com/fragment-cache/-/fragment-cache-0.2.1.tgz#4290fad27f13e89be7f33799c6bc5a0abfff0d19" 640 | integrity sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk= 641 | dependencies: 642 | map-cache "^0.2.2" 643 | 644 | fs-extra@^4.0.3: 645 | version "4.0.3" 646 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-4.0.3.tgz#0d852122e5bc5beb453fb028e9c0c9bf36340c94" 647 | integrity sha512-q6rbdDd1o2mAnQreO7YADIxf/Whx4AHBiRf6d+/cVT8h44ss+lHgxf1FemcqDnQt9X3ct4McHr+JMGlYSsK7Cg== 648 | dependencies: 649 | graceful-fs "^4.1.2" 650 | jsonfile "^4.0.0" 651 | universalify "^0.1.0" 652 | 653 | fs-extra@^7.0.1: 654 | version "7.0.1" 655 | resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9" 656 | integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw== 657 | dependencies: 658 | graceful-fs "^4.1.2" 659 | jsonfile "^4.0.0" 660 | universalify "^0.1.0" 661 | 662 | fs.realpath@^1.0.0: 663 | version "1.0.0" 664 | resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" 665 | integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= 666 | 667 | furi@^2.0.0: 668 | version "2.0.0" 669 | resolved "https://registry.yarnpkg.com/furi/-/furi-2.0.0.tgz#13d85826a1af21acc691da6254b3888fc39f0b4a" 670 | integrity sha512-uKuNsaU0WVaK/vmvj23wW1bicOFfyqSsAIH71bRZx8kA4Xj+YCHin7CJKJJjkIsmxYaPFLk9ljmjEyB7xF7WvQ== 671 | dependencies: 672 | "@types/is-windows" "^1.0.0" 673 | is-windows "^1.0.2" 674 | 675 | get-caller-file@^2.0.1: 676 | version "2.0.5" 677 | resolved "https://registry.yarnpkg.com/get-caller-file/-/get-caller-file-2.0.5.tgz#4f94412a82db32f36e3b0b9741f8a97feb031f7e" 678 | integrity sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg== 679 | 680 | get-value@^2.0.3, get-value@^2.0.6: 681 | version "2.0.6" 682 | resolved "https://registry.yarnpkg.com/get-value/-/get-value-2.0.6.tgz#dc15ca1c672387ca76bd37ac0a395ba2042a2c28" 683 | integrity sha1-3BXKHGcjh8p2vTesCjlbogQqLCg= 684 | 685 | glob-parent@^3.1.0: 686 | version "3.1.0" 687 | resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" 688 | integrity sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4= 689 | dependencies: 690 | is-glob "^3.1.0" 691 | path-dirname "^1.0.0" 692 | 693 | glob-to-regexp@^0.3.0: 694 | version "0.3.0" 695 | resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" 696 | integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs= 697 | 698 | glob@^7.0.0, glob@^7.1.3, glob@^7.1.4: 699 | version "7.1.6" 700 | resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" 701 | integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== 702 | dependencies: 703 | fs.realpath "^1.0.0" 704 | inflight "^1.0.4" 705 | inherits "2" 706 | minimatch "^3.0.4" 707 | once "^1.3.0" 708 | path-is-absolute "^1.0.0" 709 | 710 | gonzales-pe@4.3.0: 711 | version "4.3.0" 712 | resolved "https://registry.yarnpkg.com/gonzales-pe/-/gonzales-pe-4.3.0.tgz#fe9dec5f3c557eead09ff868c65826be54d067b3" 713 | integrity sha512-otgSPpUmdWJ43VXyiNgEYE4luzHCL2pz4wQ0OnDluC6Eg4Ko3Vexy/SrSynglw/eR+OhkzmqFCZa/OFa/RgAOQ== 714 | dependencies: 715 | minimist "^1.2.5" 716 | 717 | graceful-fs@^4.1.11, graceful-fs@^4.1.2, graceful-fs@^4.1.6: 718 | version "4.2.3" 719 | resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423" 720 | integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ== 721 | 722 | has-flag@^3.0.0: 723 | version "3.0.0" 724 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" 725 | integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= 726 | 727 | has-flag@^4.0.0: 728 | version "4.0.0" 729 | resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" 730 | integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== 731 | 732 | has-value@^0.3.1: 733 | version "0.3.1" 734 | resolved "https://registry.yarnpkg.com/has-value/-/has-value-0.3.1.tgz#7b1f58bada62ca827ec0a2078025654845995e1f" 735 | integrity sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8= 736 | dependencies: 737 | get-value "^2.0.3" 738 | has-values "^0.1.4" 739 | isobject "^2.0.0" 740 | 741 | has-value@^1.0.0: 742 | version "1.0.0" 743 | resolved "https://registry.yarnpkg.com/has-value/-/has-value-1.0.0.tgz#18b281da585b1c5c51def24c930ed29a0be6b177" 744 | integrity sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc= 745 | dependencies: 746 | get-value "^2.0.6" 747 | has-values "^1.0.0" 748 | isobject "^3.0.0" 749 | 750 | has-values@^0.1.4: 751 | version "0.1.4" 752 | resolved "https://registry.yarnpkg.com/has-values/-/has-values-0.1.4.tgz#6d61de95d91dfca9b9a02089ad384bff8f62b771" 753 | integrity sha1-bWHeldkd/Km5oCCJrThL/49it3E= 754 | 755 | has-values@^1.0.0: 756 | version "1.0.0" 757 | resolved "https://registry.yarnpkg.com/has-values/-/has-values-1.0.0.tgz#95b0b63fec2146619a6fe57fe75628d5a39efe4f" 758 | integrity sha1-lbC2P+whRmGab+V/51Yo1aOe/k8= 759 | dependencies: 760 | is-number "^3.0.0" 761 | kind-of "^4.0.0" 762 | 763 | html-escaper@^2.0.0: 764 | version "2.0.2" 765 | resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" 766 | integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== 767 | 768 | inflight@^1.0.4: 769 | version "1.0.6" 770 | resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" 771 | integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= 772 | dependencies: 773 | once "^1.3.0" 774 | wrappy "1" 775 | 776 | inherits@2: 777 | version "2.0.4" 778 | resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" 779 | integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== 780 | 781 | interpret@^1.0.0: 782 | version "1.2.0" 783 | resolved "https://registry.yarnpkg.com/interpret/-/interpret-1.2.0.tgz#d5061a6224be58e8083985f5014d844359576296" 784 | integrity sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw== 785 | 786 | is-accessor-descriptor@^0.1.6: 787 | version "0.1.6" 788 | resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz#a9e12cb3ae8d876727eeef3843f8a0897b5c98d6" 789 | integrity sha1-qeEss66Nh2cn7u84Q/igiXtcmNY= 790 | dependencies: 791 | kind-of "^3.0.2" 792 | 793 | is-accessor-descriptor@^1.0.0: 794 | version "1.0.0" 795 | resolved "https://registry.yarnpkg.com/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz#169c2f6d3df1f992618072365c9b0ea1f6878656" 796 | integrity sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ== 797 | dependencies: 798 | kind-of "^6.0.0" 799 | 800 | is-arrayish@^0.2.1: 801 | version "0.2.1" 802 | resolved "https://registry.yarnpkg.com/is-arrayish/-/is-arrayish-0.2.1.tgz#77c99840527aa8ecb1a8ba697b80645a7a926a9d" 803 | integrity sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0= 804 | 805 | is-buffer@^1.1.5: 806 | version "1.1.6" 807 | resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be" 808 | integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w== 809 | 810 | is-ci@^2.0.0: 811 | version "2.0.0" 812 | resolved "https://registry.yarnpkg.com/is-ci/-/is-ci-2.0.0.tgz#6bc6334181810e04b5c22b3d589fdca55026404c" 813 | integrity sha512-YfJT7rkpQB0updsdHLGWrvhBJfcfzNNawYDNIyQXJz0IViGf75O8EBPKSdvw2rF+LGCsX4FZ8tcr3b19LcZq4w== 814 | dependencies: 815 | ci-info "^2.0.0" 816 | 817 | is-data-descriptor@^0.1.4: 818 | version "0.1.4" 819 | resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz#0b5ee648388e2c860282e793f1856fec3f301b56" 820 | integrity sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y= 821 | dependencies: 822 | kind-of "^3.0.2" 823 | 824 | is-data-descriptor@^1.0.0: 825 | version "1.0.0" 826 | resolved "https://registry.yarnpkg.com/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz#d84876321d0e7add03990406abbbbd36ba9268c7" 827 | integrity sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ== 828 | dependencies: 829 | kind-of "^6.0.0" 830 | 831 | is-descriptor@^0.1.0: 832 | version "0.1.6" 833 | resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-0.1.6.tgz#366d8240dde487ca51823b1ab9f07a10a78251ca" 834 | integrity sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg== 835 | dependencies: 836 | is-accessor-descriptor "^0.1.6" 837 | is-data-descriptor "^0.1.4" 838 | kind-of "^5.0.0" 839 | 840 | is-descriptor@^1.0.0, is-descriptor@^1.0.2: 841 | version "1.0.2" 842 | resolved "https://registry.yarnpkg.com/is-descriptor/-/is-descriptor-1.0.2.tgz#3b159746a66604b04f8c81524ba365c5f14d86ec" 843 | integrity sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg== 844 | dependencies: 845 | is-accessor-descriptor "^1.0.0" 846 | is-data-descriptor "^1.0.0" 847 | kind-of "^6.0.2" 848 | 849 | is-extendable@^0.1.0, is-extendable@^0.1.1: 850 | version "0.1.1" 851 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-0.1.1.tgz#62b110e289a471418e3ec36a617d472e301dfc89" 852 | integrity sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik= 853 | 854 | is-extendable@^1.0.1: 855 | version "1.0.1" 856 | resolved "https://registry.yarnpkg.com/is-extendable/-/is-extendable-1.0.1.tgz#a7470f9e426733d81bd81e1155264e3a3507cab4" 857 | integrity sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA== 858 | dependencies: 859 | is-plain-object "^2.0.4" 860 | 861 | is-extglob@^2.1.0, is-extglob@^2.1.1: 862 | version "2.1.1" 863 | resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" 864 | integrity sha1-qIwCU1eR8C7TfHahueqXc8gz+MI= 865 | 866 | is-fullwidth-code-point@^3.0.0: 867 | version "3.0.0" 868 | resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" 869 | integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== 870 | 871 | is-glob@^3.1.0: 872 | version "3.1.0" 873 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" 874 | integrity sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo= 875 | dependencies: 876 | is-extglob "^2.1.0" 877 | 878 | is-glob@^4.0.0: 879 | version "4.0.1" 880 | resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc" 881 | integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg== 882 | dependencies: 883 | is-extglob "^2.1.1" 884 | 885 | is-number@^3.0.0: 886 | version "3.0.0" 887 | resolved "https://registry.yarnpkg.com/is-number/-/is-number-3.0.0.tgz#24fd6201a4782cf50561c810276afc7d12d71195" 888 | integrity sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU= 889 | dependencies: 890 | kind-of "^3.0.2" 891 | 892 | is-plain-object@^2.0.3, is-plain-object@^2.0.4: 893 | version "2.0.4" 894 | resolved "https://registry.yarnpkg.com/is-plain-object/-/is-plain-object-2.0.4.tgz#2c163b3fafb1b606d9d17928f05c2a1c38e07677" 895 | integrity sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og== 896 | dependencies: 897 | isobject "^3.0.1" 898 | 899 | is-windows@^1.0.2: 900 | version "1.0.2" 901 | resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d" 902 | integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA== 903 | 904 | isarray@1.0.0: 905 | version "1.0.0" 906 | resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" 907 | integrity sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE= 908 | 909 | isexe@^2.0.0: 910 | version "2.0.0" 911 | resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" 912 | integrity sha1-6PvzdNxVb/iUehDcsFctYz8s+hA= 913 | 914 | isobject@^2.0.0: 915 | version "2.1.0" 916 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-2.1.0.tgz#f065561096a3f1da2ef46272f815c840d87e0c89" 917 | integrity sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk= 918 | dependencies: 919 | isarray "1.0.0" 920 | 921 | isobject@^3.0.0, isobject@^3.0.1: 922 | version "3.0.1" 923 | resolved "https://registry.yarnpkg.com/isobject/-/isobject-3.0.1.tgz#4e431e92b11a9731636aa1f9c8d1ccbcfdab78df" 924 | integrity sha1-TkMekrEalzFjaqH5yNHMvP2reN8= 925 | 926 | istanbul-lib-coverage@^3.0.0: 927 | version "3.0.0" 928 | resolved "https://registry.yarnpkg.com/istanbul-lib-coverage/-/istanbul-lib-coverage-3.0.0.tgz#f5944a37c70b550b02a78a5c3b2055b280cec8ec" 929 | integrity sha512-UiUIqxMgRDET6eR+o5HbfRYP1l0hqkWOs7vNxC/mggutCMUIhWMm8gAHb8tHlyfD3/l6rlgNA5cKdDzEAf6hEg== 930 | 931 | istanbul-lib-report@^3.0.0: 932 | version "3.0.0" 933 | resolved "https://registry.yarnpkg.com/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz#7518fe52ea44de372f460a76b5ecda9ffb73d8a6" 934 | integrity sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw== 935 | dependencies: 936 | istanbul-lib-coverage "^3.0.0" 937 | make-dir "^3.0.0" 938 | supports-color "^7.1.0" 939 | 940 | istanbul-reports@^3.0.2: 941 | version "3.0.2" 942 | resolved "https://registry.yarnpkg.com/istanbul-reports/-/istanbul-reports-3.0.2.tgz#d593210e5000683750cb09fc0644e4b6e27fd53b" 943 | integrity sha512-9tZvz7AiR3PEDNGiV9vIouQ/EAcqMXFmkcA1CDFTwOB98OZVDL0PH9glHotf5Ugp6GCOTypfzGWI/OqjWNCRUw== 944 | dependencies: 945 | html-escaper "^2.0.0" 946 | istanbul-lib-report "^3.0.0" 947 | 948 | jasmine-core@~3.6.0: 949 | version "3.6.0" 950 | resolved "https://registry.yarnpkg.com/jasmine-core/-/jasmine-core-3.6.0.tgz#491f3bb23941799c353ceb7a45b38a950ebc5a20" 951 | integrity sha512-8uQYa7zJN8hq9z+g8z1bqCfdC8eoDAeVnM5sfqs7KHv9/ifoJ500m018fpFc7RDaO6SWCLCXwo/wPSNcdYTgcw== 952 | 953 | jasmine-reporters@~2.3.2: 954 | version "2.3.2" 955 | resolved "https://registry.yarnpkg.com/jasmine-reporters/-/jasmine-reporters-2.3.2.tgz#898818ffc234eb8b3f635d693de4586f95548d43" 956 | integrity sha512-u/7AT9SkuZsUfFBLLzbErohTGNsEUCKaQbsVYnLFW1gEuL2DzmBL4n8v90uZsqIqlWvWUgian8J6yOt5Fyk/+A== 957 | dependencies: 958 | mkdirp "^0.5.1" 959 | xmldom "^0.1.22" 960 | 961 | jasmine@3.6.1: 962 | version "3.6.1" 963 | resolved "https://registry.yarnpkg.com/jasmine/-/jasmine-3.6.1.tgz#a20456b309a669b547a3c24bb2120f16f70cfc65" 964 | integrity sha512-Jqp8P6ZWkTVFGmJwBK46p+kJNrZCdqkQ4GL+PGuBXZwK1fM4ST9BizkYgIwCFqYYqnTizAy6+XG2Ej5dFrej9Q== 965 | dependencies: 966 | fast-glob "^2.2.6" 967 | jasmine-core "~3.6.0" 968 | 969 | json-parse-better-errors@^1.0.1: 970 | version "1.0.2" 971 | resolved "https://registry.yarnpkg.com/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz#bb867cfb3450e69107c131d1c514bab3dc8bcaa9" 972 | integrity sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw== 973 | 974 | json5@^1.0.1: 975 | version "1.0.1" 976 | resolved "https://registry.yarnpkg.com/json5/-/json5-1.0.1.tgz#779fb0018604fa854eacbf6252180d83543e3dbe" 977 | integrity sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow== 978 | dependencies: 979 | minimist "^1.2.0" 980 | 981 | jsonfile@^4.0.0: 982 | version "4.0.0" 983 | resolved "https://registry.yarnpkg.com/jsonfile/-/jsonfile-4.0.0.tgz#8771aae0799b64076b76640fca058f9c10e33ecb" 984 | integrity sha1-h3Gq4HmbZAdrdmQPygWPnBDjPss= 985 | optionalDependencies: 986 | graceful-fs "^4.1.6" 987 | 988 | kind-of@^3.0.2, kind-of@^3.0.3, kind-of@^3.2.0: 989 | version "3.2.2" 990 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-3.2.2.tgz#31ea21a734bab9bbb0f32466d893aea51e4a3c64" 991 | integrity sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ= 992 | dependencies: 993 | is-buffer "^1.1.5" 994 | 995 | kind-of@^4.0.0: 996 | version "4.0.0" 997 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-4.0.0.tgz#20813df3d712928b207378691a45066fae72dd57" 998 | integrity sha1-IIE989cSkosgc3hpGkUGb65y3Vc= 999 | dependencies: 1000 | is-buffer "^1.1.5" 1001 | 1002 | kind-of@^5.0.0: 1003 | version "5.1.0" 1004 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-5.1.0.tgz#729c91e2d857b7a419a1f9aa65685c4c33f5845d" 1005 | integrity sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw== 1006 | 1007 | kind-of@^6.0.0, kind-of@^6.0.2: 1008 | version "6.0.3" 1009 | resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" 1010 | integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== 1011 | 1012 | klaw-sync@^6.0.0: 1013 | version "6.0.0" 1014 | resolved "https://registry.yarnpkg.com/klaw-sync/-/klaw-sync-6.0.0.tgz#1fd2cfd56ebb6250181114f0a581167099c2b28c" 1015 | integrity sha512-nIeuVSzdCCs6TDPTqI8w1Yre34sSq7AkZ4B3sfOBbI2CgVSB4Du4aLQijFU2+lhAFCwt9+42Hel6lQNIv6AntQ== 1016 | dependencies: 1017 | graceful-fs "^4.1.11" 1018 | 1019 | load-json-file@^4.0.0: 1020 | version "4.0.0" 1021 | resolved "https://registry.yarnpkg.com/load-json-file/-/load-json-file-4.0.0.tgz#2f5f45ab91e33216234fd53adab668eb4ec0993b" 1022 | integrity sha1-L19Fq5HjMhYjT9U62rZo607AmTs= 1023 | dependencies: 1024 | graceful-fs "^4.1.2" 1025 | parse-json "^4.0.0" 1026 | pify "^3.0.0" 1027 | strip-bom "^3.0.0" 1028 | 1029 | locate-path@^2.0.0: 1030 | version "2.0.0" 1031 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-2.0.0.tgz#2b568b265eec944c6d9c0de9c3dbbbca0354cd8e" 1032 | integrity sha1-K1aLJl7slExtnA3pw9u7ygNUzY4= 1033 | dependencies: 1034 | p-locate "^2.0.0" 1035 | path-exists "^3.0.0" 1036 | 1037 | locate-path@^5.0.0: 1038 | version "5.0.0" 1039 | resolved "https://registry.yarnpkg.com/locate-path/-/locate-path-5.0.0.tgz#1afba396afd676a6d42504d0a67a3a7eb9f62aa0" 1040 | integrity sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g== 1041 | dependencies: 1042 | p-locate "^4.1.0" 1043 | 1044 | lodash.kebabcase@4.1.1: 1045 | version "4.1.1" 1046 | resolved "https://registry.yarnpkg.com/lodash.kebabcase/-/lodash.kebabcase-4.1.1.tgz#8489b1cb0d29ff88195cceca448ff6d6cc295c36" 1047 | integrity sha1-hImxyw0p/4gZXM7KRI/21swpXDY= 1048 | 1049 | long@^4.0.0: 1050 | version "4.0.0" 1051 | resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" 1052 | integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== 1053 | 1054 | make-dir@^3.0.0: 1055 | version "3.1.0" 1056 | resolved "https://registry.yarnpkg.com/make-dir/-/make-dir-3.1.0.tgz#415e967046b3a7f1d185277d84aa58203726a13f" 1057 | integrity sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw== 1058 | dependencies: 1059 | semver "^6.0.0" 1060 | 1061 | map-cache@^0.2.2: 1062 | version "0.2.2" 1063 | resolved "https://registry.yarnpkg.com/map-cache/-/map-cache-0.2.2.tgz#c32abd0bd6525d9b051645bb4f26ac5dc98a0dbf" 1064 | integrity sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8= 1065 | 1066 | map-visit@^1.0.0: 1067 | version "1.0.0" 1068 | resolved "https://registry.yarnpkg.com/map-visit/-/map-visit-1.0.0.tgz#ecdca8f13144e660f1b5bd41f12f3479d98dfb8f" 1069 | integrity sha1-7Nyo8TFE5mDxtb1B8S80edmN+48= 1070 | dependencies: 1071 | object-visit "^1.0.0" 1072 | 1073 | merge2@^1.2.3: 1074 | version "1.4.1" 1075 | resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" 1076 | integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== 1077 | 1078 | micromatch@^3.1.10, micromatch@^3.1.4: 1079 | version "3.1.10" 1080 | resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" 1081 | integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== 1082 | dependencies: 1083 | arr-diff "^4.0.0" 1084 | array-unique "^0.3.2" 1085 | braces "^2.3.1" 1086 | define-property "^2.0.2" 1087 | extend-shallow "^3.0.2" 1088 | extglob "^2.0.4" 1089 | fragment-cache "^0.2.1" 1090 | kind-of "^6.0.2" 1091 | nanomatch "^1.2.9" 1092 | object.pick "^1.3.0" 1093 | regex-not "^1.0.0" 1094 | snapdragon "^0.8.1" 1095 | to-regex "^3.0.2" 1096 | 1097 | minimatch@3.0.4, minimatch@^3.0.4: 1098 | version "3.0.4" 1099 | resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" 1100 | integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== 1101 | dependencies: 1102 | brace-expansion "^1.1.7" 1103 | 1104 | minimist@^1.2.0, minimist@^1.2.5: 1105 | version "1.2.5" 1106 | resolved "https://registry.yarnpkg.com/minimist/-/minimist-1.2.5.tgz#67d66014b66a6a8aaa0c083c5fd58df4e4e97602" 1107 | integrity sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw== 1108 | 1109 | mixin-deep@^1.2.0: 1110 | version "1.3.2" 1111 | resolved "https://registry.yarnpkg.com/mixin-deep/-/mixin-deep-1.3.2.tgz#1120b43dc359a785dce65b55b82e257ccf479566" 1112 | integrity sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA== 1113 | dependencies: 1114 | for-in "^1.0.2" 1115 | is-extendable "^1.0.1" 1116 | 1117 | mkdirp@^0.5.1: 1118 | version "0.5.5" 1119 | resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.5.tgz#d91cefd62d1436ca0f41620e251288d420099def" 1120 | integrity sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ== 1121 | dependencies: 1122 | minimist "^1.2.5" 1123 | 1124 | mock-fs@4.12.0: 1125 | version "4.12.0" 1126 | resolved "https://registry.yarnpkg.com/mock-fs/-/mock-fs-4.12.0.tgz#a5d50b12d2d75e5bec9dac3b67ffe3c41d31ade4" 1127 | integrity sha512-/P/HtrlvBxY4o/PzXY9cCNBrdylDNxg7gnrv2sMNxj+UJ2m8jSpl0/A6fuJeNAWr99ZvGWH8XCbE0vmnM5KupQ== 1128 | 1129 | ms@2.0.0: 1130 | version "2.0.0" 1131 | resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" 1132 | integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= 1133 | 1134 | nanomatch@^1.2.9: 1135 | version "1.2.13" 1136 | resolved "https://registry.yarnpkg.com/nanomatch/-/nanomatch-1.2.13.tgz#b87a8aa4fc0de8fe6be88895b38983ff265bd119" 1137 | integrity sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA== 1138 | dependencies: 1139 | arr-diff "^4.0.0" 1140 | array-unique "^0.3.2" 1141 | define-property "^2.0.2" 1142 | extend-shallow "^3.0.2" 1143 | fragment-cache "^0.2.1" 1144 | is-windows "^1.0.2" 1145 | kind-of "^6.0.2" 1146 | object.pick "^1.3.0" 1147 | regex-not "^1.0.0" 1148 | snapdragon "^0.8.1" 1149 | to-regex "^3.0.1" 1150 | 1151 | nice-try@^1.0.4: 1152 | version "1.0.5" 1153 | resolved "https://registry.yarnpkg.com/nice-try/-/nice-try-1.0.5.tgz#a3378a7696ce7d223e88fc9b764bd7ef1089e366" 1154 | integrity sha512-1nh45deeb5olNY7eX82BkPO7SSxR5SSYJiPTrTdFUVYwAl8CKMA5N9PjTYkHiRjisVcxcQ1HXdLhx2qxxJzLNQ== 1155 | 1156 | object-copy@^0.1.0: 1157 | version "0.1.0" 1158 | resolved "https://registry.yarnpkg.com/object-copy/-/object-copy-0.1.0.tgz#7e7d858b781bd7c991a41ba975ed3812754e998c" 1159 | integrity sha1-fn2Fi3gb18mRpBupde04EnVOmYw= 1160 | dependencies: 1161 | copy-descriptor "^0.1.0" 1162 | define-property "^0.2.5" 1163 | kind-of "^3.0.3" 1164 | 1165 | object-visit@^1.0.0: 1166 | version "1.0.1" 1167 | resolved "https://registry.yarnpkg.com/object-visit/-/object-visit-1.0.1.tgz#f79c4493af0c5377b59fe39d395e41042dd045bb" 1168 | integrity sha1-95xEk68MU3e1n+OdOV5BBC3QRbs= 1169 | dependencies: 1170 | isobject "^3.0.0" 1171 | 1172 | object.pick@^1.3.0: 1173 | version "1.3.0" 1174 | resolved "https://registry.yarnpkg.com/object.pick/-/object.pick-1.3.0.tgz#87a10ac4c1694bd2e1cbf53591a66141fb5dd747" 1175 | integrity sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c= 1176 | dependencies: 1177 | isobject "^3.0.1" 1178 | 1179 | once@^1.3.0: 1180 | version "1.4.0" 1181 | resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" 1182 | integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= 1183 | dependencies: 1184 | wrappy "1" 1185 | 1186 | os-tmpdir@~1.0.2: 1187 | version "1.0.2" 1188 | resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" 1189 | integrity sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ= 1190 | 1191 | p-limit@^1.1.0: 1192 | version "1.3.0" 1193 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-1.3.0.tgz#b86bd5f0c25690911c7590fcbfc2010d54b3ccb8" 1194 | integrity sha512-vvcXsLAJ9Dr5rQOPk7toZQZJApBl2K4J6dANSsEuh6QI41JYcsS/qhTGa9ErIUUgK3WNQoJYvylxvjqmiqEA9Q== 1195 | dependencies: 1196 | p-try "^1.0.0" 1197 | 1198 | p-limit@^2.2.0: 1199 | version "2.3.0" 1200 | resolved "https://registry.yarnpkg.com/p-limit/-/p-limit-2.3.0.tgz#3dd33c647a214fdfffd835933eb086da0dc21db1" 1201 | integrity sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w== 1202 | dependencies: 1203 | p-try "^2.0.0" 1204 | 1205 | p-locate@^2.0.0: 1206 | version "2.0.0" 1207 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-2.0.0.tgz#20a0103b222a70c8fd39cc2e580680f3dde5ec43" 1208 | integrity sha1-IKAQOyIqcMj9OcwuWAaA893l7EM= 1209 | dependencies: 1210 | p-limit "^1.1.0" 1211 | 1212 | p-locate@^4.1.0: 1213 | version "4.1.0" 1214 | resolved "https://registry.yarnpkg.com/p-locate/-/p-locate-4.1.0.tgz#a3428bb7088b3a60292f66919278b7c297ad4f07" 1215 | integrity sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A== 1216 | dependencies: 1217 | p-limit "^2.2.0" 1218 | 1219 | p-try@^1.0.0: 1220 | version "1.0.0" 1221 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-1.0.0.tgz#cbc79cdbaf8fd4228e13f621f2b1a237c1b207b3" 1222 | integrity sha1-y8ec26+P1CKOE/Yh8rGiN8GyB7M= 1223 | 1224 | p-try@^2.0.0: 1225 | version "2.2.0" 1226 | resolved "https://registry.yarnpkg.com/p-try/-/p-try-2.2.0.tgz#cb2868540e313d61de58fafbe35ce9004d5540e6" 1227 | integrity sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ== 1228 | 1229 | parse-json@^4.0.0: 1230 | version "4.0.0" 1231 | resolved "https://registry.yarnpkg.com/parse-json/-/parse-json-4.0.0.tgz#be35f5425be1f7f6c747184f98a788cb99477ee0" 1232 | integrity sha1-vjX1Qlvh9/bHRxhPmKeIy5lHfuA= 1233 | dependencies: 1234 | error-ex "^1.3.1" 1235 | json-parse-better-errors "^1.0.1" 1236 | 1237 | pascalcase@^0.1.1: 1238 | version "0.1.1" 1239 | resolved "https://registry.yarnpkg.com/pascalcase/-/pascalcase-0.1.1.tgz#b363e55e8006ca6fe21784d2db22bd15d7917f14" 1240 | integrity sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ= 1241 | 1242 | patch-package@6.2.2: 1243 | version "6.2.2" 1244 | resolved "https://registry.yarnpkg.com/patch-package/-/patch-package-6.2.2.tgz#71d170d650c65c26556f0d0fbbb48d92b6cc5f39" 1245 | integrity sha512-YqScVYkVcClUY0v8fF0kWOjDYopzIM8e3bj/RU1DPeEF14+dCGm6UeOYm4jvCyxqIEQ5/eJzmbWfDWnUleFNMg== 1246 | dependencies: 1247 | "@yarnpkg/lockfile" "^1.1.0" 1248 | chalk "^2.4.2" 1249 | cross-spawn "^6.0.5" 1250 | find-yarn-workspace-root "^1.2.1" 1251 | fs-extra "^7.0.1" 1252 | is-ci "^2.0.0" 1253 | klaw-sync "^6.0.0" 1254 | minimist "^1.2.0" 1255 | rimraf "^2.6.3" 1256 | semver "^5.6.0" 1257 | slash "^2.0.0" 1258 | tmp "^0.0.33" 1259 | 1260 | path-dirname@^1.0.0: 1261 | version "1.0.2" 1262 | resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" 1263 | integrity sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA= 1264 | 1265 | path-exists@^3.0.0: 1266 | version "3.0.0" 1267 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" 1268 | integrity sha1-zg6+ql94yxiSXqfYENe1mwEP1RU= 1269 | 1270 | path-exists@^4.0.0: 1271 | version "4.0.0" 1272 | resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3" 1273 | integrity sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w== 1274 | 1275 | path-is-absolute@^1.0.0: 1276 | version "1.0.1" 1277 | resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" 1278 | integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= 1279 | 1280 | path-key@^2.0.1: 1281 | version "2.0.1" 1282 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-2.0.1.tgz#411cadb574c5a140d3a4b1910d40d80cc9f40b40" 1283 | integrity sha1-QRyttXTFoUDTpLGRDUDYDMn0C0A= 1284 | 1285 | path-key@^3.1.0: 1286 | version "3.1.1" 1287 | resolved "https://registry.yarnpkg.com/path-key/-/path-key-3.1.1.tgz#581f6ade658cbba65a0d3380de7753295054f375" 1288 | integrity sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q== 1289 | 1290 | path-parse@^1.0.6: 1291 | version "1.0.6" 1292 | resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" 1293 | integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== 1294 | 1295 | pify@^3.0.0: 1296 | version "3.0.0" 1297 | resolved "https://registry.yarnpkg.com/pify/-/pify-3.0.0.tgz#e5a4acd2c101fdf3d9a4d07f0dbc4db49dd28176" 1298 | integrity sha1-5aSs0sEB/fPZpNB/DbxNtJ3SgXY= 1299 | 1300 | pkg-conf@^2.1.0: 1301 | version "2.1.0" 1302 | resolved "https://registry.yarnpkg.com/pkg-conf/-/pkg-conf-2.1.0.tgz#2126514ca6f2abfebd168596df18ba57867f0058" 1303 | integrity sha1-ISZRTKbyq/69FoWW3xi6V4Z/AFg= 1304 | dependencies: 1305 | find-up "^2.0.0" 1306 | load-json-file "^4.0.0" 1307 | 1308 | posix-character-classes@^0.1.0: 1309 | version "0.1.1" 1310 | resolved "https://registry.yarnpkg.com/posix-character-classes/-/posix-character-classes-0.1.1.tgz#01eac0fe3b5af71a2a6c02feabb8c1fef7e00eab" 1311 | integrity sha1-AerA/jta9xoqbAL+q7jB/vfgDqs= 1312 | 1313 | protobufjs@6.8.8: 1314 | version "6.8.8" 1315 | resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-6.8.8.tgz#c8b4f1282fd7a90e6f5b109ed11c84af82908e7c" 1316 | integrity sha512-AAmHtD5pXgZfi7GMpllpO3q1Xw1OYldr+dMUlAnffGTAhqkg72WdmSY71uKBF/JuyiKs8psYbtKrhi0ASCD8qw== 1317 | dependencies: 1318 | "@protobufjs/aspromise" "^1.1.2" 1319 | "@protobufjs/base64" "^1.1.2" 1320 | "@protobufjs/codegen" "^2.0.4" 1321 | "@protobufjs/eventemitter" "^1.1.0" 1322 | "@protobufjs/fetch" "^1.1.0" 1323 | "@protobufjs/float" "^1.0.2" 1324 | "@protobufjs/inquire" "^1.1.0" 1325 | "@protobufjs/path" "^1.1.2" 1326 | "@protobufjs/pool" "^1.1.0" 1327 | "@protobufjs/utf8" "^1.1.0" 1328 | "@types/long" "^4.0.0" 1329 | "@types/node" "^10.1.0" 1330 | long "^4.0.0" 1331 | 1332 | rechoir@^0.6.2: 1333 | version "0.6.2" 1334 | resolved "https://registry.yarnpkg.com/rechoir/-/rechoir-0.6.2.tgz#85204b54dba82d5742e28c96756ef43af50e3384" 1335 | integrity sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q= 1336 | dependencies: 1337 | resolve "^1.1.6" 1338 | 1339 | regex-not@^1.0.0, regex-not@^1.0.2: 1340 | version "1.0.2" 1341 | resolved "https://registry.yarnpkg.com/regex-not/-/regex-not-1.0.2.tgz#1f4ece27e00b0b65e0247a6810e6a85d83a5752c" 1342 | integrity sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A== 1343 | dependencies: 1344 | extend-shallow "^3.0.2" 1345 | safe-regex "^1.1.0" 1346 | 1347 | repeat-element@^1.1.2: 1348 | version "1.1.3" 1349 | resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce" 1350 | integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g== 1351 | 1352 | repeat-string@^1.6.1: 1353 | version "1.6.1" 1354 | resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637" 1355 | integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc= 1356 | 1357 | require-directory@^2.1.1: 1358 | version "2.1.1" 1359 | resolved "https://registry.yarnpkg.com/require-directory/-/require-directory-2.1.1.tgz#8c64ad5fd30dab1c976e2344ffe7f792a6a6df42" 1360 | integrity sha1-jGStX9MNqxyXbiNE/+f3kqam30I= 1361 | 1362 | require-main-filename@^2.0.0: 1363 | version "2.0.0" 1364 | resolved "https://registry.yarnpkg.com/require-main-filename/-/require-main-filename-2.0.0.tgz#d0b329ecc7cc0f61649f62215be69af54aa8989b" 1365 | integrity sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg== 1366 | 1367 | resolve-url@^0.2.1: 1368 | version "0.2.1" 1369 | resolved "https://registry.yarnpkg.com/resolve-url/-/resolve-url-0.2.1.tgz#2c637fe77c893afd2a663fe21aa9080068e2052a" 1370 | integrity sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo= 1371 | 1372 | resolve@^1.1.6: 1373 | version "1.17.0" 1374 | resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.17.0.tgz#b25941b54968231cc2d1bb76a79cb7f2c0bf8444" 1375 | integrity sha512-ic+7JYiV8Vi2yzQGFWOkiZD5Z9z7O2Zhm9XMaTxdJExKasieFCr+yXZ/WmXsckHiKl12ar0y6XiXDx3m4RHn1w== 1376 | dependencies: 1377 | path-parse "^1.0.6" 1378 | 1379 | ret@~0.1.10: 1380 | version "0.1.15" 1381 | resolved "https://registry.yarnpkg.com/ret/-/ret-0.1.15.tgz#b8a4825d5bdb1fc3f6f53c2bc33f81388681c7bc" 1382 | integrity sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg== 1383 | 1384 | rimraf@^2.6.3: 1385 | version "2.7.1" 1386 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.7.1.tgz#35797f13a7fdadc566142c29d4f07ccad483e3ec" 1387 | integrity sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w== 1388 | dependencies: 1389 | glob "^7.1.3" 1390 | 1391 | rimraf@^3.0.0: 1392 | version "3.0.2" 1393 | resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-3.0.2.tgz#f1a5402ba6220ad52cc1282bac1ae3aa49fd061a" 1394 | integrity sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA== 1395 | dependencies: 1396 | glob "^7.1.3" 1397 | 1398 | safe-buffer@~5.1.1: 1399 | version "5.1.2" 1400 | resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" 1401 | integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== 1402 | 1403 | safe-regex@^1.1.0: 1404 | version "1.1.0" 1405 | resolved "https://registry.yarnpkg.com/safe-regex/-/safe-regex-1.1.0.tgz#40a3669f3b077d1e943d44629e157dd48023bf2e" 1406 | integrity sha1-QKNmnzsHfR6UPURinhV91IAjvy4= 1407 | dependencies: 1408 | ret "~0.1.10" 1409 | 1410 | semver@5.6.0: 1411 | version "5.6.0" 1412 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.6.0.tgz#7e74256fbaa49c75aa7c7a205cc22799cac80004" 1413 | integrity sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg== 1414 | 1415 | semver@^5.5.0, semver@^5.6.0: 1416 | version "5.7.1" 1417 | resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" 1418 | integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== 1419 | 1420 | semver@^6.0.0: 1421 | version "6.3.0" 1422 | resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.0.tgz#ee0a64c8af5e8ceea67687b133761e1becbd1d3d" 1423 | integrity sha512-b39TBaTSfV6yBrapU89p5fKekE2m/NwnDocOVruQFS1/veMgdzuPcnOM34M6CwxW8jH/lxEa5rBoDeUwu5HHTw== 1424 | 1425 | semver@^7.0.0: 1426 | version "7.3.2" 1427 | resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.2.tgz#604962b052b81ed0786aae84389ffba70ffd3938" 1428 | integrity sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ== 1429 | 1430 | set-blocking@^2.0.0: 1431 | version "2.0.0" 1432 | resolved "https://registry.yarnpkg.com/set-blocking/-/set-blocking-2.0.0.tgz#045f9782d011ae9a6803ddd382b24392b3d890f7" 1433 | integrity sha1-BF+XgtARrppoA93TgrJDkrPYkPc= 1434 | 1435 | set-value@^2.0.0, set-value@^2.0.1: 1436 | version "2.0.1" 1437 | resolved "https://registry.yarnpkg.com/set-value/-/set-value-2.0.1.tgz#a18d40530e6f07de4228c7defe4227af8cad005b" 1438 | integrity sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw== 1439 | dependencies: 1440 | extend-shallow "^2.0.1" 1441 | is-extendable "^0.1.1" 1442 | is-plain-object "^2.0.3" 1443 | split-string "^3.0.1" 1444 | 1445 | shebang-command@^1.2.0: 1446 | version "1.2.0" 1447 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-1.2.0.tgz#44aac65b695b03398968c39f363fee5deafdf1ea" 1448 | integrity sha1-RKrGW2lbAzmJaMOfNj/uXer98eo= 1449 | dependencies: 1450 | shebang-regex "^1.0.0" 1451 | 1452 | shebang-command@^2.0.0: 1453 | version "2.0.0" 1454 | resolved "https://registry.yarnpkg.com/shebang-command/-/shebang-command-2.0.0.tgz#ccd0af4f8835fbdc265b82461aaf0c36663f34ea" 1455 | integrity sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA== 1456 | dependencies: 1457 | shebang-regex "^3.0.0" 1458 | 1459 | shebang-regex@^1.0.0: 1460 | version "1.0.0" 1461 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-1.0.0.tgz#da42f49740c0b42db2ca9728571cb190c98efea3" 1462 | integrity sha1-2kL0l0DAtC2yypcoVxyxkMmO/qM= 1463 | 1464 | shebang-regex@^3.0.0: 1465 | version "3.0.0" 1466 | resolved "https://registry.yarnpkg.com/shebang-regex/-/shebang-regex-3.0.0.tgz#ae16f1644d873ecad843b0307b143362d4c42172" 1467 | integrity sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A== 1468 | 1469 | shelljs@0.8.4: 1470 | version "0.8.4" 1471 | resolved "https://registry.yarnpkg.com/shelljs/-/shelljs-0.8.4.tgz#de7684feeb767f8716b326078a8a00875890e3c2" 1472 | integrity sha512-7gk3UZ9kOfPLIAbslLzyWeGiEqx9e3rxwZM0KE6EL8GlGwjym9Mrlx5/p33bWTu9YG6vcS4MBxYZDHYr5lr8BQ== 1473 | dependencies: 1474 | glob "^7.0.0" 1475 | interpret "^1.0.0" 1476 | rechoir "^0.6.2" 1477 | 1478 | signal-exit@^3.0.2: 1479 | version "3.0.3" 1480 | resolved "https://registry.yarnpkg.com/signal-exit/-/signal-exit-3.0.3.tgz#a1410c2edd8f077b08b4e253c8eacfcaf057461c" 1481 | integrity sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA== 1482 | 1483 | signale@1.4.0: 1484 | version "1.4.0" 1485 | resolved "https://registry.yarnpkg.com/signale/-/signale-1.4.0.tgz#c4be58302fb0262ac00fc3d886a7c113759042f1" 1486 | integrity sha512-iuh+gPf28RkltuJC7W5MRi6XAjTDCAPC/prJUpQoG4vIP3MJZ+GTydVnodXA7pwvTKb2cA0m9OFZW/cdWy/I/w== 1487 | dependencies: 1488 | chalk "^2.3.2" 1489 | figures "^2.0.0" 1490 | pkg-conf "^2.1.0" 1491 | 1492 | slash@^2.0.0: 1493 | version "2.0.0" 1494 | resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" 1495 | integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== 1496 | 1497 | snapdragon-node@^2.0.1: 1498 | version "2.1.1" 1499 | resolved "https://registry.yarnpkg.com/snapdragon-node/-/snapdragon-node-2.1.1.tgz#6c175f86ff14bdb0724563e8f3c1b021a286853b" 1500 | integrity sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw== 1501 | dependencies: 1502 | define-property "^1.0.0" 1503 | isobject "^3.0.0" 1504 | snapdragon-util "^3.0.1" 1505 | 1506 | snapdragon-util@^3.0.1: 1507 | version "3.0.1" 1508 | resolved "https://registry.yarnpkg.com/snapdragon-util/-/snapdragon-util-3.0.1.tgz#f956479486f2acd79700693f6f7b805e45ab56e2" 1509 | integrity sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ== 1510 | dependencies: 1511 | kind-of "^3.2.0" 1512 | 1513 | snapdragon@^0.8.1: 1514 | version "0.8.2" 1515 | resolved "https://registry.yarnpkg.com/snapdragon/-/snapdragon-0.8.2.tgz#64922e7c565b0e14204ba1aa7d6964278d25182d" 1516 | integrity sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg== 1517 | dependencies: 1518 | base "^0.11.1" 1519 | debug "^2.2.0" 1520 | define-property "^0.2.5" 1521 | extend-shallow "^2.0.1" 1522 | map-cache "^0.2.2" 1523 | source-map "^0.5.6" 1524 | source-map-resolve "^0.5.0" 1525 | use "^3.1.0" 1526 | 1527 | source-map-resolve@^0.5.0: 1528 | version "0.5.3" 1529 | resolved "https://registry.yarnpkg.com/source-map-resolve/-/source-map-resolve-0.5.3.tgz#190866bece7553e1f8f267a2ee82c606b5509a1a" 1530 | integrity sha512-Htz+RnsXWk5+P2slx5Jh3Q66vhQj1Cllm0zvnaY98+NFx+Dv2CF/f5O/t8x+KaNdrdIAsruNzoh/KpialbqAnw== 1531 | dependencies: 1532 | atob "^2.1.2" 1533 | decode-uri-component "^0.2.0" 1534 | resolve-url "^0.2.1" 1535 | source-map-url "^0.4.0" 1536 | urix "^0.1.0" 1537 | 1538 | source-map-support@0.5.9: 1539 | version "0.5.9" 1540 | resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.9.tgz#41bc953b2534267ea2d605bccfa7bfa3111ced5f" 1541 | integrity sha512-gR6Rw4MvUlYy83vP0vxoVNzM6t8MUXqNuRsuBmBHQDu1Fh6X015FrLdgoDKcNdkwGubozq0P4N0Q37UyFVr1EA== 1542 | dependencies: 1543 | buffer-from "^1.0.0" 1544 | source-map "^0.6.0" 1545 | 1546 | source-map-url@^0.4.0: 1547 | version "0.4.0" 1548 | resolved "https://registry.yarnpkg.com/source-map-url/-/source-map-url-0.4.0.tgz#3e935d7ddd73631b97659956d55128e87b5084a3" 1549 | integrity sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM= 1550 | 1551 | source-map@^0.5.6: 1552 | version "0.5.7" 1553 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.5.7.tgz#8a039d2d1021d22d1ea14c80d8ea468ba2ef3fcc" 1554 | integrity sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w= 1555 | 1556 | source-map@^0.6.0: 1557 | version "0.6.1" 1558 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.6.1.tgz#74722af32e9614e9c287a8d0bbde48b5e2f1a263" 1559 | integrity sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g== 1560 | 1561 | source-map@^0.7.3: 1562 | version "0.7.3" 1563 | resolved "https://registry.yarnpkg.com/source-map/-/source-map-0.7.3.tgz#5302f8169031735226544092e64981f751750383" 1564 | integrity sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ== 1565 | 1566 | split-string@^3.0.1, split-string@^3.0.2: 1567 | version "3.1.0" 1568 | resolved "https://registry.yarnpkg.com/split-string/-/split-string-3.1.0.tgz#7cb09dda3a86585705c64b39a6466038682e8fe2" 1569 | integrity sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw== 1570 | dependencies: 1571 | extend-shallow "^3.0.0" 1572 | 1573 | static-extend@^0.1.1: 1574 | version "0.1.2" 1575 | resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6" 1576 | integrity sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY= 1577 | dependencies: 1578 | define-property "^0.2.5" 1579 | object-copy "^0.1.0" 1580 | 1581 | string-width@^4.1.0, string-width@^4.2.0: 1582 | version "4.2.0" 1583 | resolved "https://registry.yarnpkg.com/string-width/-/string-width-4.2.0.tgz#952182c46cc7b2c313d1596e623992bd163b72b5" 1584 | integrity sha512-zUz5JD+tgqtuDjMhwIg5uFVV3dtqZ9yQJlZVfq4I01/K5Paj5UHj7VyrQOJvzawSVlKpObApbfD0Ed6yJc+1eg== 1585 | dependencies: 1586 | emoji-regex "^8.0.0" 1587 | is-fullwidth-code-point "^3.0.0" 1588 | strip-ansi "^6.0.0" 1589 | 1590 | strip-ansi@^6.0.0: 1591 | version "6.0.0" 1592 | resolved "https://registry.yarnpkg.com/strip-ansi/-/strip-ansi-6.0.0.tgz#0b1571dd7669ccd4f3e06e14ef1eed26225ae532" 1593 | integrity sha512-AuvKTrTfQNYNIctbR1K/YGTR1756GycPsg7b9bdV9Duqur4gv6aKqHXah67Z8ImS7WEz5QVcOtlfW2rZEugt6w== 1594 | dependencies: 1595 | ansi-regex "^5.0.0" 1596 | 1597 | strip-bom@^3.0.0: 1598 | version "3.0.0" 1599 | resolved "https://registry.yarnpkg.com/strip-bom/-/strip-bom-3.0.0.tgz#2334c18e9c759f7bdd56fdef7e9ae3d588e68ed3" 1600 | integrity sha1-IzTBjpx1n3vdVv3vfprj1YjmjtM= 1601 | 1602 | supports-color@^5.3.0: 1603 | version "5.5.0" 1604 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" 1605 | integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== 1606 | dependencies: 1607 | has-flag "^3.0.0" 1608 | 1609 | supports-color@^7.1.0: 1610 | version "7.1.0" 1611 | resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-7.1.0.tgz#68e32591df73e25ad1c4b49108a2ec507962bfd1" 1612 | integrity sha512-oRSIpR8pxT1Wr2FquTNnGet79b3BWljqOuoW/h4oBhxJ/HUbX5nX6JSruTkvXDCFMwDPvsaTTbvMLKZWSy0R5g== 1613 | dependencies: 1614 | has-flag "^4.0.0" 1615 | 1616 | test-exclude@^6.0.0: 1617 | version "6.0.0" 1618 | resolved "https://registry.yarnpkg.com/test-exclude/-/test-exclude-6.0.0.tgz#04a8698661d805ea6fa293b6cb9e63ac044ef15e" 1619 | integrity sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w== 1620 | dependencies: 1621 | "@istanbuljs/schema" "^0.1.2" 1622 | glob "^7.1.4" 1623 | minimatch "^3.0.4" 1624 | 1625 | tmp@^0.0.33: 1626 | version "0.0.33" 1627 | resolved "https://registry.yarnpkg.com/tmp/-/tmp-0.0.33.tgz#6d34335889768d21b2bcda0aa277ced3b1bfadf9" 1628 | integrity sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw== 1629 | dependencies: 1630 | os-tmpdir "~1.0.2" 1631 | 1632 | to-object-path@^0.3.0: 1633 | version "0.3.0" 1634 | resolved "https://registry.yarnpkg.com/to-object-path/-/to-object-path-0.3.0.tgz#297588b7b0e7e0ac08e04e672f85c1f4999e17af" 1635 | integrity sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68= 1636 | dependencies: 1637 | kind-of "^3.0.2" 1638 | 1639 | to-regex-range@^2.1.0: 1640 | version "2.1.1" 1641 | resolved "https://registry.yarnpkg.com/to-regex-range/-/to-regex-range-2.1.1.tgz#7c80c17b9dfebe599e27367e0d4dd5590141db38" 1642 | integrity sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg= 1643 | dependencies: 1644 | is-number "^3.0.0" 1645 | repeat-string "^1.6.1" 1646 | 1647 | to-regex@^3.0.1, to-regex@^3.0.2: 1648 | version "3.0.2" 1649 | resolved "https://registry.yarnpkg.com/to-regex/-/to-regex-3.0.2.tgz#13cfdd9b336552f30b51f33a8ae1b42a7a7599ce" 1650 | integrity sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw== 1651 | dependencies: 1652 | define-property "^2.0.2" 1653 | extend-shallow "^3.0.2" 1654 | regex-not "^1.0.2" 1655 | safe-regex "^1.1.0" 1656 | 1657 | tsconfig-paths@3.9.0: 1658 | version "3.9.0" 1659 | resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.9.0.tgz#098547a6c4448807e8fcb8eae081064ee9a3c90b" 1660 | integrity sha512-dRcuzokWhajtZWkQsDVKbWyY+jgcLC5sqJhg2PSgf4ZkH2aHPvaOY8YWGhmjb68b5qqTfasSsDO9k7RUiEmZAw== 1661 | dependencies: 1662 | "@types/json5" "^0.0.29" 1663 | json5 "^1.0.1" 1664 | minimist "^1.2.0" 1665 | strip-bom "^3.0.0" 1666 | 1667 | tslib@^1.8.1: 1668 | version "1.11.1" 1669 | resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.11.1.tgz#eb15d128827fbee2841549e171f45ed338ac7e35" 1670 | integrity sha512-aZW88SY8kQbU7gpV19lN24LtXh/yD4ZZg6qieAJDDg+YBsJcSmLGK9QpnUjAKVG/xefmvJGd1WUmfpT/g6AJGA== 1671 | 1672 | tsutils@2.27.2: 1673 | version "2.27.2" 1674 | resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.27.2.tgz#60ba88a23d6f785ec4b89c6e8179cac9b431f1c7" 1675 | integrity sha512-qf6rmT84TFMuxAKez2pIfR8UCai49iQsfB7YWVjV1bKpy/d0PWT5rEOSM6La9PiHZ0k1RRZQiwVdVJfQ3BPHgg== 1676 | dependencies: 1677 | tslib "^1.8.1" 1678 | 1679 | typescript@3.8.3: 1680 | version "3.8.3" 1681 | resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.8.3.tgz#409eb8544ea0335711205869ec458ab109ee1061" 1682 | integrity sha512-MYlEfn5VrLNsgudQTVJeNaQFUAI7DkhnOjdpAp4T+ku1TfQClewlbSuTVHiA+8skNBgaf02TL/kLOvig4y3G8w== 1683 | 1684 | union-value@^1.0.0: 1685 | version "1.0.1" 1686 | resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847" 1687 | integrity sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg== 1688 | dependencies: 1689 | arr-union "^3.1.0" 1690 | get-value "^2.0.6" 1691 | is-extendable "^0.1.1" 1692 | set-value "^2.0.1" 1693 | 1694 | universalify@^0.1.0: 1695 | version "0.1.2" 1696 | resolved "https://registry.yarnpkg.com/universalify/-/universalify-0.1.2.tgz#b646f69be3942dabcecc9d6639c80dc105efaa66" 1697 | integrity sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg== 1698 | 1699 | unset-value@^1.0.0: 1700 | version "1.0.0" 1701 | resolved "https://registry.yarnpkg.com/unset-value/-/unset-value-1.0.0.tgz#8376873f7d2335179ffb1e6fc3a8ed0dfc8ab559" 1702 | integrity sha1-g3aHP30jNRef+x5vw6jtDfyKtVk= 1703 | dependencies: 1704 | has-value "^0.3.1" 1705 | isobject "^3.0.0" 1706 | 1707 | urix@^0.1.0: 1708 | version "0.1.0" 1709 | resolved "https://registry.yarnpkg.com/urix/-/urix-0.1.0.tgz#da937f7a62e21fec1fd18d49b35c2935067a6c72" 1710 | integrity sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI= 1711 | 1712 | use@^3.1.0: 1713 | version "3.1.1" 1714 | resolved "https://registry.yarnpkg.com/use/-/use-3.1.1.tgz#d50c8cac79a19fbc20f2911f56eb973f4e10070f" 1715 | integrity sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ== 1716 | 1717 | v8-to-istanbul@^4.1.2: 1718 | version "4.1.4" 1719 | resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-4.1.4.tgz#b97936f21c0e2d9996d4985e5c5156e9d4e49cd6" 1720 | integrity sha512-Rw6vJHj1mbdK8edjR7+zuJrpDtKIgNdAvTSAcpYfgMIw+u2dPDntD3dgN4XQFLU2/fvFQdzj+EeSGfd/jnY5fQ== 1721 | dependencies: 1722 | "@types/istanbul-lib-coverage" "^2.0.1" 1723 | convert-source-map "^1.6.0" 1724 | source-map "^0.7.3" 1725 | 1726 | which-module@^2.0.0: 1727 | version "2.0.0" 1728 | resolved "https://registry.yarnpkg.com/which-module/-/which-module-2.0.0.tgz#d9ef07dce77b9902b8a3a8fa4b31c3e3f7e6e87a" 1729 | integrity sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho= 1730 | 1731 | which@^1.2.9: 1732 | version "1.3.1" 1733 | resolved "https://registry.yarnpkg.com/which/-/which-1.3.1.tgz#a45043d54f5805316da8d62f9f50918d3da70b0a" 1734 | integrity sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ== 1735 | dependencies: 1736 | isexe "^2.0.0" 1737 | 1738 | which@^2.0.1: 1739 | version "2.0.2" 1740 | resolved "https://registry.yarnpkg.com/which/-/which-2.0.2.tgz#7c6a8dd0a636a0327e10b59c9286eee93f3f51b1" 1741 | integrity sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA== 1742 | dependencies: 1743 | isexe "^2.0.0" 1744 | 1745 | wrap-ansi@^6.2.0: 1746 | version "6.2.0" 1747 | resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-6.2.0.tgz#e9393ba07102e6c91a3b221478f0257cd2856e53" 1748 | integrity sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA== 1749 | dependencies: 1750 | ansi-styles "^4.0.0" 1751 | string-width "^4.1.0" 1752 | strip-ansi "^6.0.0" 1753 | 1754 | wrappy@1: 1755 | version "1.0.2" 1756 | resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" 1757 | integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= 1758 | 1759 | xmldom@^0.1.22: 1760 | version "0.1.31" 1761 | resolved "https://registry.yarnpkg.com/xmldom/-/xmldom-0.1.31.tgz#b76c9a1bd9f0a9737e5a72dc37231cf38375e2ff" 1762 | integrity sha512-yS2uJflVQs6n+CyjHoaBmVSqIDevTAWrzMmjG1Gc7h1qQ7uVozNhEPJAwZXWyGQ/Gafo3fCwrcaokezLPupVyQ== 1763 | 1764 | y18n@^4.0.0: 1765 | version "4.0.0" 1766 | resolved "https://registry.yarnpkg.com/y18n/-/y18n-4.0.0.tgz#95ef94f85ecc81d007c264e190a120f0a3c8566b" 1767 | integrity sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w== 1768 | 1769 | yargs-parser@^18.0.0, yargs-parser@^18.1.2: 1770 | version "18.1.3" 1771 | resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-18.1.3.tgz#be68c4975c6b2abf469236b0c870362fab09a7b0" 1772 | integrity sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ== 1773 | dependencies: 1774 | camelcase "^5.0.0" 1775 | decamelize "^1.2.0" 1776 | 1777 | yargs@15.4.1, yargs@^15.0.0: 1778 | version "15.4.1" 1779 | resolved "https://registry.yarnpkg.com/yargs/-/yargs-15.4.1.tgz#0d87a16de01aee9d8bec2bfbf74f67851730f4f8" 1780 | integrity sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A== 1781 | dependencies: 1782 | cliui "^6.0.0" 1783 | decamelize "^1.2.0" 1784 | find-up "^4.1.0" 1785 | get-caller-file "^2.0.1" 1786 | require-directory "^2.1.1" 1787 | require-main-filename "^2.0.0" 1788 | set-blocking "^2.0.0" 1789 | string-width "^4.2.0" 1790 | which-module "^2.0.0" 1791 | y18n "^4.0.0" 1792 | yargs-parser "^18.1.2" 1793 | --------------------------------------------------------------------------------