Merge pull request #43 from antvis/encode

feat(core): add map method
This commit is contained in:
@thinkinggis 2019-10-21 14:43:02 +08:00 committed by GitHub
commit 9782c51d89
25 changed files with 23143 additions and 49 deletions

22818
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@ -38,7 +38,7 @@
"enzyme-adapter-react-16": "^1.5.0",
"enzyme-to-json": "^3.0.0-beta6",
"html-webpack-plugin": "^3.2.0",
"husky": "^3.0.4",
"husky": "^3.0.9",
"jest": "^24.9.0",
"jest-styled-components": "^6.2.1",
"lerna": "^3.16.4",
@ -97,6 +97,7 @@
],
"husky": {
"hooks": {
"pre-commit": "npm run lint",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
},

View File

@ -1,4 +1,5 @@
import container, { lazyInject } from './inversify.config';
import IconService from './services/asset/IconService';
import ClearPass from './services/renderer/passes/ClearPass';
import MultiPassRenderer from './services/renderer/passes/MultiPassRenderer';
import PixelPickingPass from './services/renderer/passes/PixelPickingPass';
@ -27,6 +28,7 @@ export {
* Service
*/
SceneService,
IconService,
packCircleVertex,
/** pass */
MultiPassRenderer,

View File

@ -18,6 +18,8 @@ export interface IIconService {
canvasHeight: number;
init(): void;
addImage(id: string, image: IImage): void;
hasImage(id: string): boolean;
removeImage(id: string): void;
getTexture(): ITexture2D;
getIconMap(): IICONMap;
getCanvas(): HTMLCanvasElement;

View File

@ -61,6 +61,13 @@ export default class IconService implements IIconService {
return this.canvas;
}
public hasImage(id: string): boolean {
throw new Error('Method not implemented.');
}
public removeImage(id: string): void {
throw new Error('Method not implemented.');
}
private updateIconAtlas() {
this.canvas.width = MAX_CANVAS_WIDTH;
this.canvas.height = this.canvasHeight;

View File

@ -1,8 +1,7 @@
import { ISourceCFG } from '@l7/core';
import { AsyncParallelHook, SyncHook } from 'tapable';
import { IModel } from '../renderer/IModel';
import { IMultiPassRenderer } from '../renderer/IMultiPassRenderer';
import { ISource } from '../source/ISourceService';
import { ISource, ISourceCFG } from '../source/ISourceService';
import { ILayerStyleOptions } from './ILayerStyleService';
export enum ScaleTypes {
LINEAR = 'linear',

View File

@ -1,10 +1,41 @@
import { IViewport } from '../camera/ICameraService';
export type Point = [number, number];
export type Bounds = [[number, number], [number, number]];
export interface ILngLat {
lng: number;
lat: number;
}
export interface IPoint {
x: number;
y: number;
}
export interface IMapService {
init(config: Partial<IMapConfig>): void;
onCameraChanged(callback: (viewport: IViewport) => void): void;
}
// get map status method
getZoom(): number;
getCenter(): ILngLat;
getPitch(): number;
getRotation(): number;
getBounds(): Bounds;
// set Map status
setRotation(rotation: number): void;
zoomIn(): void;
zoomOut(): void;
panTo(p: Point): void;
panBy(pixel: Point): void;
fitBounds(bound: Bounds): void;
setZoomAndCenter(zoom: number, center: Point): void;
setMapStyle(style: string): void;
// conversion Method
pixelToLngLat(pixel: Point): ILngLat;
lngLatToPixel(lnglat: Point): IPoint;
containerToLngLat(pixel: Point): ILngLat;
lngLatToContainer(lnglat: Point): IPoint;
}
export enum MapType {
amap = 'amap',
mapbox = 'mapbox',

View File

@ -3,11 +3,9 @@ import { ILayer } from '../layer/ILayerService';
import { IMapConfig } from '../map/IMapService';
import { IRenderConfig } from '../renderer/IRendererService';
export interface ISceneService {
init(config: IMapConfig & IRenderConfig): void;
addLayer(layer: ILayer): void;
addImage(id: string, image: IImage): void;
render(): void;
destroy(): void;
}

View File

@ -18,6 +18,8 @@ import { ISceneService } from './ISceneService';
*/
@injectable()
export default class Scene extends EventEmitter implements ISceneService {
@inject(TYPES.IIconService)
public readonly iconService: IIconService;
/**
* 使 Service
*/
@ -45,9 +47,6 @@ export default class Scene extends EventEmitter implements ISceneService {
@inject(TYPES.IShaderModuleService)
private readonly shaderModule: IShaderModuleService;
@inject(TYPES.IIconService)
private readonly iconService: IIconService;
/**
*
*/
@ -79,10 +78,8 @@ export default class Scene extends EventEmitter implements ISceneService {
public init(globalConfig: IGlobalConfig) {
this.configService.setAndCheckConfig(globalConfig);
// 初始化资源管理 字体,图片
this.iconService.init();
this.iconService.init();
/**
*
*/
@ -158,10 +155,6 @@ export default class Scene extends EventEmitter implements ISceneService {
this.interactionService.destroy();
window.removeEventListener('resize', this.handleWindowResized, false);
}
public addImage(id: string, img: IImage) {
this.iconService.addImage(id, img);
}
private handleWindowResized = () => {
this.emit('resize');
if (this.$container) {

View File

@ -21,6 +21,7 @@
"dependencies": {
"@l7/core": "^0.0.1",
"@l7/source": "^0.0.1",
"@l7/utils": "^0.0.1",
"@turf/meta": "^6.0.2",
"@types/d3-color": "^1.2.2",
"d3-array": "^2.3.1",

View File

@ -40,8 +40,6 @@ export default class HeatMapLayer extends BaseLayer {
const buffer = new GridHeatMapBuffer({
data: this.getEncodedData(),
});
console.log(this.getSource());
console.log(buffer);
const {
createAttribute,
createBuffer,

View File

@ -39,7 +39,6 @@ export default class LineLayer extends BaseLayer {
data: this.getEncodedData(),
style: this.styleOption,
});
console.log(buffer);
const {
createAttribute,
createBuffer,

View File

@ -4,12 +4,12 @@ import {
ILayerPlugin,
ILayerStyleAttribute,
IParseDataItem,
ISourceCFG,
IStyleScale,
lazyInject,
StyleScaleType,
TYPES,
} from '@l7/core';
import { ISourceCFG } from '@l7/core';
import Source from '@l7/source';
export default class DataSourcePlugin implements ILayerPlugin {
public apply(layer: ILayer) {

View File

@ -23,7 +23,6 @@ export default class PointLayer extends BaseLayer {
@lazyInject(TYPES.IRendererService)
private readonly renderer: IRendererService;
protected renderModels() {
this.models.forEach((model) =>
model.draw({

View File

@ -27,6 +27,7 @@
"viewport-mercator-project": "^6.2.1"
},
"devDependencies": {
"@types/amap-js-api": "^1.4.6",
"@types/gl-matrix": "^2.4.5",
"@types/mapbox-gl": "^0.54.3",
"@types/viewport-mercator-project": "^6.1.0"

View File

@ -2,12 +2,16 @@
* AMapService
*/
import {
Bounds,
CoordinateSystem,
ICoordinateSystemService,
ILngLat,
IMapCamera,
IMapConfig,
IMapService,
IPoint,
IViewport,
Point,
TYPES,
} from '@l7/core';
import { inject, injectable } from 'inversify';
@ -17,6 +21,8 @@ const AMAP_API_KEY: string = '15cd8a57710d40c9b7c0e3cc120f1200';
const AMAP_VERSION: string = '1.4.8';
const LNGLAT_OFFSET_ZOOM_THRESHOLD = 12;
/// <reference path="../../../../../node_modules/@types/amap-js-api/index.d.ts" />
/**
* AMapService
*/
@ -25,11 +31,90 @@ export default class AMapService implements IMapService {
@inject(TYPES.ICoordinateSystemService)
private readonly coordinateSystemService: ICoordinateSystemService;
private map: IAMapInstance;
private map: AMap.Map;
private viewport: Viewport;
private cameraChangedCallback: (viewport: IViewport) => void;
public getZoom(): number {
return this.map.getZoom();
}
public getCenter(): ILngLat {
const center = this.map.getCenter();
return {
lng: center.getLng(),
lat: center.getLat(),
};
}
public getPitch(): number {
return this.map.getPitch();
}
public getRotation(): number {
return this.map.getRotation();
}
public getBounds(): Bounds {
// @ts-ignore
const amapBound = this.map.getBounds().toBounds();
const NE = amapBound.getNorthEast();
const SW = amapBound.getSouthWest();
return [[NE.getLng(), NE.getLat()], [SW.getLng(), SW.getLat()]];
}
public setRotation(rotation: number): number {
return this.setRotation(rotation);
}
public zoomIn(): void {
this.map.zoomIn();
}
public zoomOut(): void {
this.map.zoomOut();
}
public panTo(p: [number, number]): void {
this.map.panTo(p);
}
public panBy(pixel: [number, number]): void {
this.map.panTo(pixel);
}
public fitBounds(extent: Bounds): void {
this.map.setBounds(
new AMap.Bounds([extent[0][0], extent[0][1], extent[1][0], extent[1][1]]),
);
}
public setZoomAndCenter(zoom: number, center: [number, number]): void {
this.map.setZoomAndCenter(zoom, center);
}
public setMapStyle(style: string): void {
this.setMapStyle(style);
}
public pixelToLngLat(pixel: [number, number]): ILngLat {
const lngLat = this.map.pixelToLngLat(new AMap.Pixel(pixel[0], pixel[1]));
return { lng: lngLat.getLng(), lat: lngLat.getLat() };
}
public lngLatToPixel(lnglat: [number, number]): IPoint {
const p = this.map.lnglatToPixel(new AMap.LngLat(lnglat[0], lnglat[1]));
return {
x: p.getX(),
y: p.getY(),
};
}
public containerToLngLat(pixel: [number, number]): ILngLat {
const ll = new AMap.Pixel(pixel[0], pixel[1]);
const lngLat = this.map.containerToLngLat(ll);
return {
lng: lngLat.getLng(),
lat: lngLat.getLat(),
};
}
public lngLatToContainer(lnglat: [number, number]): IPoint {
const ll = new AMap.LngLat(lnglat[0], lnglat[1]);
const pixel = this.map.lngLatToContainer(ll);
return {
x: pixel.getX(),
y: pixel.getY(),
};
}
public async init(mapConfig: IMapConfig): Promise<void> {
const { id, style, ...rest } = mapConfig;
@ -76,7 +161,7 @@ export default class AMapService implements IMapService {
aspect,
position,
} = e.camera;
const { lng, lat } = this.map.getCenter();
const { lng, lat } = this.getCenter();
if (this.cameraChangedCallback) {
// resync viewport

View File

@ -2,15 +2,18 @@
* MapboxService
*/
import {
Bounds,
CoordinateSystem,
ICoordinateSystemService,
ILngLat,
IMapConfig,
IMapService,
IPoint,
IViewport,
TYPES,
} from '@l7/core';
import { inject, injectable } from 'inversify';
import mapboxgl from 'mapbox-gl';
import mapboxgl, { Map } from 'mapbox-gl';
import Viewport from './Viewport';
mapboxgl.accessToken =
@ -25,9 +28,69 @@ export default class MapboxService implements IMapService {
@inject(TYPES.ICoordinateSystemService)
private readonly coordinateSystemService: ICoordinateSystemService;
private map: IMapboxInstance;
private map: Map & IMapboxInstance;
private viewport: Viewport;
private cameraChangedCallback: (viewport: IViewport) => void;
public getZoom(): number {
return this.map.getZoom();
}
public getCenter(): ILngLat {
return this.map.getCenter();
}
public getPitch(): number {
return this.map.getPitch();
}
public getRotation(): number {
return this.map.getBearing();
}
public getBounds(): Bounds {
return this.map.getBounds().toArray() as Bounds;
}
public setRotation(rotation: number): void {
this.map.setBearing(rotation);
}
public zoomIn(): void {
this.map.zoomIn();
}
public zoomOut(): void {
this.map.zoomOut();
}
public panTo(p: [number, number]): void {
this.map.panTo(p);
}
public panBy(pixel: [number, number]): void {
this.panTo(pixel);
}
public fitBounds(bound: Bounds): void {
this.map.fitBounds(bound);
}
public setMaxZoom(max: number): void {
this.map.setMaxZoom(max);
}
public setMinZoom(min: number): void {
this.map.setMinZoom(min);
}
public setZoomAndCenter(zoom: number, center: [number, number]): void {
this.map.flyTo({
zoom,
center,
});
}
public setMapStyle(style: string): void {
this.map.setStyle(style);
}
public pixelToLngLat(pixel: [number, number]): ILngLat {
return this.map.unproject(pixel);
}
public lngLatToPixel(lnglat: [number, number]): IPoint {
return this.map.project(lnglat);
}
public containerToLngLat(pixel: [number, number]): ILngLat {
throw new Error('Method not implemented.');
}
public lngLatToContainer(lnglat: [number, number]): IPoint {
throw new Error('Method not implemented.');
}
public async init(mapConfig: IMapConfig): Promise<void> {
const { id, ...rest } = mapConfig;

View File

@ -1,7 +1,7 @@
/// <reference path="../../../node_modules/@types/amap-js-api/index.d.ts" />
interface Window {
onLoad: () => void;
}
interface IAMapEvent {
camera: {
fov: number;
@ -19,14 +19,10 @@ interface IAMapInstance {
on(eventName: string, handler: (event: IAMapEvent) => void): void;
getZoom(): number;
getCenter(): {lat: number; lng: number};
[key:string]: Function;
}
interface IMapboxInstance {
on(eventName: string, handler: () => void): void;
getZoom(): number;
getPitch(): number;
getBearing(): number;
getCenter(): any;
transform: {
width: number;
height: number;

View File

@ -1,25 +1,31 @@
import {
Bounds,
container,
IconService,
IIconService,
IImage,
ILayer,
ILngLat,
IMapConfig,
IMapService,
IPoint,
IRenderConfig,
IRendererService,
ISceneService,
MapType,
Point,
SceneService,
TYPES,
} from '@l7/core';
import { AMapService, MapboxService } from '@l7/maps';
import { ReglRendererService } from '@l7/renderer';
import { inject, injectable } from 'inversify';
// 绑定渲染引擎服务
container
.bind<IRendererService>(TYPES.IRendererService)
.to(ReglRendererService)
.inSingletonScope();
/**
* Scene API
*
@ -33,8 +39,10 @@ container
* scene.render();
*/
class Scene {
@inject(TYPES.IIconService)
protected readonly iconService: IIconService;
private sceneService: ISceneService;
private mapService: IMapService;
public constructor(config: IMapConfig & IRenderConfig) {
const { type = MapType.amap } = config;
@ -47,7 +55,7 @@ class Scene {
} else {
throw new Error('不支持的地图服务');
}
// this.mapService = mapService;
// DEMO 中切换底图实现时,需要重新绑定底图服务
// @see https://github.com/inversify/InversifyJS/blob/master/wiki/container_api.md#containerrebindserviceidentifier-serviceidentifier
if (container.isBound(TYPES.IMapService)) {
@ -65,6 +73,8 @@ class Scene {
// 依赖注入
this.sceneService = container.resolve(SceneService);
this.sceneService.init(config);
this.mapService = container.get<IMapService>(TYPES.IMapService);
this.iconService = container.get<IIconService>(TYPES.IIconService);
}
public addLayer(layer: ILayer): void {
@ -74,9 +84,70 @@ class Scene {
public render(): void {
this.sceneService.render();
}
// asset method
public addImage(id: string, img: IImage) {
this.sceneService.addImage(id, img);
// this.sceneService.
this.iconService.addImage(id, img);
}
// map method
public getZoom(): number {
return this.mapService.getZoom();
}
public getCenter(): ILngLat {
return this.mapService.getCenter();
}
public getPitch(): number {
return this.mapService.getPitch();
}
public getRotation(): number {
return this.mapService.getRotation();
}
public getBounds(): Bounds {
return this.mapService.getBounds();
}
// set Map status
public setRotation(rotation: number): void {
this.mapService.setRotation(rotation);
}
public zoomIn(): void {
this.mapService.zoomIn();
}
public zoomOut(): void {
this.mapService.zoomOut();
}
public panTo(p: Point): void {
this.mapService.panTo(p);
}
public panBy(pixel: Point): void {
this.mapService.panTo(pixel);
}
public fitBounds(bound: Bounds): void {
this.mapService.fitBounds(bound);
}
public setZoomAndCenter(zoom: number, center: Point): void {
this.mapService.setZoomAndCenter(zoom, center);
}
public setMapStyle(style: string): void {
this.mapService.setMapStyle(style);
}
// conversion Method
public pixelToLngLat(pixel: Point): ILngLat {
return this.mapService.pixelToLngLat(pixel);
}
public lngLatToPixel(lnglat: Point): IPoint {
return this.mapService.lngLatToPixel(lnglat);
}
public containerToLngLat(pixel: Point): ILngLat {
return this.mapService.containerToLngLat(pixel);
}
public lngLatToContainer(lnglat: Point): IPoint {
return this.mapService.lngLatToContainer(lnglat);
}
public destroy() {
this.sceneService.destroy();
}

View File

@ -21,8 +21,8 @@
"author": "lzxue",
"license": "ISC",
"dependencies": {
"@l7/utils": "0.0.1",
"@l7/core": "0.0.1",
"@l7/utils": "0.0.1",
"@mapbox/geojson-rewind": "^0.4.0",
"@turf/helpers": "^6.1.4",
"@turf/invariant": "^6.1.2",
@ -35,6 +35,7 @@
"inversify-logging": "^0.2.1",
"lodash": "^4.17.15",
"reflect-metadata": "^0.1.13",
"supercluster": "^6.0.2",
"tapable": "^2.0.0-beta.8"
},
"devDependencies": {

View File

@ -1,5 +1,5 @@
import { csvParse } from 'd3-dsv';
import { IJsonData, IParserCfg, IParserData } from '@l7/core';
import { csvParse } from 'd3-dsv';
import json from './json';
export default function csv(data: string, cfg: IParserCfg): IParserData {
const csvData: IJsonData = csvParse(data);

View File

@ -1,5 +1,4 @@
// @ts-ignore
import rewind from '@mapbox/geojson-rewind';
import {
IJsonData,
IJsonItem,
@ -7,6 +6,8 @@ import {
IParserCfg,
IParserData,
} from '@l7/core';
// @ts-ignore
import rewind from '@mapbox/geojson-rewind';
export default function json(data: IJsonData, cfg: IParserCfg): IParserData {
const { x, y, x1, y1, coordinates } = cfg;
const resultData: IParseDataItem[] = [];

View File

@ -75,13 +75,7 @@ export default class Mapbox extends React.Component {
opacity: 0.8,
});
scene.addLayer(layer);
function run() {
scene.render();
requestAnimationFrame(run);
}
requestAnimationFrame(run);
this.scene = scene;
console.log(layer);
scene.render();
/*** 运行时修改样式属性 ***/
// const gui = new dat.GUI();
// this.gui = gui;

View File

@ -26,5 +26,5 @@
"useCache": false
},
"include": ["packages"],
"exclude": ["node_modules", "packages/**/dist"]
"exclude": ["node_modules", "packages/**/dist"],
}

View File

@ -2709,6 +2709,11 @@
dependencies:
"@turf/helpers" "6.x"
"@types/amap-js-api@^1.4.6":
version "1.4.6"
resolved "https://registry.yarnpkg.com/@types/amap-js-api/-/amap-js-api-1.4.6.tgz#7239c450dac1b3c08c32203c205a63e99a64b3a1"
integrity sha512-qZMM+sv4GJQ0jm5aekxoomS4bv5N3KClAAscPUe9BEKirVpewCkn6doliuZXU9eOrYz2CXy3qg4L6KzIfK0zaw==
"@types/babel__core@^7.1.0":
version "7.1.2"
resolved "https://registry.yarnpkg.com/@types/babel__core/-/babel__core-7.1.2.tgz#608c74f55928033fce18b99b213c16be4b3d114f"
@ -4995,7 +5000,7 @@ concat-map@0.0.1:
resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b"
integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=
concat-stream@^1.5.0, concat-stream@~1.6.0:
concat-stream@^1.4.7, concat-stream@^1.5.0, concat-stream@~1.6.0:
version "1.6.2"
resolved "https://registry.yarnpkg.com/concat-stream/-/concat-stream-1.6.2.tgz#904bdf194cd3122fc675c77fc4ac3d4ff0fd1a34"
integrity sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==
@ -10916,6 +10921,11 @@ os-name@^3.0.0:
macos-release "^2.2.0"
windows-release "^3.1.0"
os-shim@^0.1.2:
version "0.1.3"
resolved "https://registry.yarnpkg.com/os-shim/-/os-shim-0.1.3.tgz#6b62c3791cf7909ea35ed46e17658bb417cb3917"
integrity sha1-a2LDeRz3kJ6jXtRuF2WLtBfLORc=
os-tmpdir@^1.0.0, os-tmpdir@~1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274"
@ -11611,6 +11621,15 @@ potpack@^1.0.1:
resolved "https://registry.yarnpkg.com/potpack/-/potpack-1.0.1.tgz#d1b1afd89e4c8f7762865ec30bd112ab767e2ebf"
integrity sha512-15vItUAbViaYrmaB/Pbw7z6qX2xENbFSTA7Ii4tgbPtasxm5v6ryKhKtL91tpWovDJzTiZqdwzhcFBCwiMVdVw==
pre-commit@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/pre-commit/-/pre-commit-1.2.2.tgz#dbcee0ee9de7235e57f79c56d7ce94641a69eec6"
integrity sha1-287g7p3nI15X95xW186UZBpp7sY=
dependencies:
cross-spawn "^5.0.1"
spawn-sync "^1.0.15"
which "1.2.x"
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@ -13460,6 +13479,14 @@ space-separated-tokens@^1.0.0:
resolved "https://registry.yarnpkg.com/space-separated-tokens/-/space-separated-tokens-1.1.4.tgz#27910835ae00d0adfcdbd0ad7e611fb9544351fa"
integrity sha512-UyhMSmeIqZrQn2UdjYpxEkwY9JUrn8pP+7L4f91zRzOQuI8MF1FGLfYU9DKCYeLdo7LXMxwrX5zKFy7eeeVHuA==
spawn-sync@^1.0.15:
version "1.0.15"
resolved "https://registry.yarnpkg.com/spawn-sync/-/spawn-sync-1.0.15.tgz#b00799557eb7fb0c8376c29d44e8a1ea67e57476"
integrity sha1-sAeZVX63+wyDdsKdROih6mfldHY=
dependencies:
concat-stream "^1.4.7"
os-shim "^0.1.2"
spdx-correct@^3.0.0:
version "3.1.0"
resolved "https://registry.yarnpkg.com/spdx-correct/-/spdx-correct-3.1.0.tgz#fb83e504445268f154b074e218c87c003cd31df4"
@ -13972,7 +13999,7 @@ sugarss@^2.0.0:
dependencies:
postcss "^7.0.2"
supercluster@^6.0.1:
supercluster@^6.0.1, supercluster@^6.0.2:
version "6.0.2"
resolved "https://registry.yarnpkg.com/supercluster/-/supercluster-6.0.2.tgz#aa2eaae185ef97872f388c683ec29f6991721ee3"
integrity sha512-aa0v2HURjBTOpbcknilcfxGDuArM8khklKSmZ/T8ZXL0BuRwb5aRw95lz+2bmWpFvCXDX/+FzqHxmg0TIaJErw==
@ -15146,6 +15173,13 @@ which@1, which@^1.2.14, which@^1.2.9, which@^1.3.0, which@^1.3.1:
dependencies:
isexe "^2.0.0"
which@1.2.x:
version "1.2.14"
resolved "https://registry.yarnpkg.com/which/-/which-1.2.14.tgz#9a87c4378f03e827cecaf1acdf56c736c01c14e5"
integrity sha1-mofEN48D6CfOyvGs31bHNsAcFOU=
dependencies:
isexe "^2.0.0"
wide-align@^1.1.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/wide-align/-/wide-align-1.1.3.tgz#ae074e6bdc0c14a431e804e624549c633b000457"