diff --git a/.circleci/config.yml b/.circleci/config.yml
index 854fadfc..d271bbd8 100644
--- a/.circleci/config.yml
+++ b/.circleci/config.yml
@@ -7,17 +7,17 @@ aliases:
# https://github.com/CircleCI-Public/circleci-dockerfiles/tree/master/node/images
- &use_docker_node
docker:
- - image: circleci/node:13.4.0-stretch
+ - image: circleci/node:13.5.0-stretch
- &use_docker_node_browsers
docker:
- - image: circleci/node:13.4.0-stretch-browsers
+ - image: circleci/node:13.5.0-stretch-browsers
# https://github.com/cypress-io/cypress-docker-images/tree/master/included
- &use_docker_cypress_included
docker:
# 3.8.0 fails with `Error: write EPIPE` when running `benchmark`!?
- - image: cypress/included:3.7.0
+ - image: cypress/included:3.8.2
- &workspace ~/talus
diff --git a/.nxignore b/.nxignore
new file mode 100644
index 00000000..34902dd4
--- /dev/null
+++ b/.nxignore
@@ -0,0 +1,2 @@
+# Hack for getting benchmark app (generated with ng g @nrwl/node:application) through linting
+/apps/benchmark
diff --git a/apps/benchmark/src/app/vdb/grid.benchmark.ts b/apps/benchmark/src/app/vdb/grid.benchmark.ts
index 94e46c7c..6cde5004 100644
--- a/apps/benchmark/src/app/vdb/grid.benchmark.ts
+++ b/apps/benchmark/src/app/vdb/grid.benchmark.ts
@@ -46,7 +46,7 @@ suite('[Grid] setValue()', () => {
for (let x = 0; x < i; x++) {
for (let y = 0; y < i; y++) {
for (let z = 0; z < i; z++) {
- accessor.setValue([x, y, z], i);
+ accessor.setValueOn([x, y, z], i);
}
}
}
diff --git a/apps/benchmark/src/app/vdb/node-to-mesh.benchmark.ts b/apps/benchmark/src/app/vdb/node-to-mesh.benchmark.ts
new file mode 100644
index 00000000..b06dcd42
--- /dev/null
+++ b/apps/benchmark/src/app/vdb/node-to-mesh.benchmark.ts
@@ -0,0 +1,34 @@
+import { benchmark, suite } from '../../main';
+
+suite('[NodeToMesh] array.push()', () => {
+ benchmark('multiple small push', () => {
+ const positions: number[] = [];
+
+ positions.push(1);
+ positions.push(2);
+ positions.push(3);
+ positions.push(4);
+ positions.push(5);
+ positions.push(6);
+ positions.push(7);
+ positions.push(8);
+ positions.push(9);
+ positions.push(10);
+ positions.push(11);
+ positions.push(12);
+ positions.push(13);
+ positions.push(14);
+ positions.push(15);
+ positions.push(16);
+ positions.push(17);
+ positions.push(18);
+ positions.push(19);
+ positions.push(20);
+ });
+
+ benchmark('single big push', () => {
+ const positions: number[] = [];
+
+ positions.push(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20);
+ });
+});
diff --git a/apps/benchmark/src/main.ts b/apps/benchmark/src/main.ts
index 10319c92..d6bb2c68 100644
--- a/apps/benchmark/src/main.ts
+++ b/apps/benchmark/src/main.ts
@@ -86,7 +86,9 @@ function convertToTestSuite(suiteName: string, currentSuite: Benchmark.Suite): T
}
function sumUpTotalTime(): void {
- report.time = report.suites.map(s => s.time).reduce((previous, current) => previous + current, 0);
+ report.time = report.suites
+ .map(s => s.time)
+ .reduce((previous, current) => (previous && current ? previous + current : 0), 0);
}
function everySuiteFinished(): boolean {
diff --git a/apps/benchmark/tslint.json b/apps/benchmark/tslint.json
index 04809f83..8e2f21b3 100644
--- a/apps/benchmark/tslint.json
+++ b/apps/benchmark/tslint.json
@@ -1 +1,4 @@
-{ "extends": "../../tslint.json", "rules": [] }
+{
+ "extends": "../../tslint.json",
+ "rules": {}
+}
diff --git a/apps/frontend/src/app/app.actions.ts b/apps/frontend/src/app/app.actions.ts
index ab592e7e..d2d34e5c 100644
--- a/apps/frontend/src/app/app.actions.ts
+++ b/apps/frontend/src/app/app.actions.ts
@@ -1,6 +1,6 @@
import { createAction } from '@ngrx/store';
-const actionTypePrefix = '[App]';
+const actionTypePrefix = '[app]';
export const wentOnline = createAction(`${actionTypePrefix} Went online`);
export const wentOffline = createAction(`${actionTypePrefix} Went offline`);
diff --git a/apps/frontend/src/app/app.component.scss b/apps/frontend/src/app/app.component.scss
new file mode 100644
index 00000000..f2cbf979
--- /dev/null
+++ b/apps/frontend/src/app/app.component.scss
@@ -0,0 +1,11 @@
+:host {
+ display: flex;
+ flex-flow: column;
+ height: 100%;
+}
+
+main {
+ flex-grow: 1;
+ // https://stackoverflow.com/a/38383437
+ min-height: 0;
+}
diff --git a/apps/frontend/src/app/app.component.spec.ts b/apps/frontend/src/app/app.component.spec.ts
index 4605e2a5..49deb6a1 100644
--- a/apps/frontend/src/app/app.component.spec.ts
+++ b/apps/frontend/src/app/app.component.spec.ts
@@ -2,9 +2,16 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
import { async, TestBed } from '@angular/core/testing';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterTestingModule } from '@angular/router/testing';
-import { SceneViewerTestModule, SidenavShellModule } from '@talus/ui';
+import { UiSceneViewerTestModule, UiSidenavShellModule } from '@talus/ui';
import { AppComponent } from './app.component';
+@Component({
+ selector: 'fe-menu-bar-container',
+ template: '',
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+class MenuBarContainerStubComponent {}
+
@Component({
selector: 'fe-scene-viewer-container',
template: '',
@@ -22,12 +29,17 @@ class ToolsPanelStubComponent {}
describe('AppComponent', () => {
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [AppComponent, SceneViewerContainerStubComponent, ToolsPanelStubComponent],
+ declarations: [
+ AppComponent,
+ MenuBarContainerStubComponent,
+ SceneViewerContainerStubComponent,
+ ToolsPanelStubComponent,
+ ],
imports: [
BrowserAnimationsModule,
RouterTestingModule,
- SidenavShellModule,
- SceneViewerTestModule,
+ UiSceneViewerTestModule,
+ UiSidenavShellModule,
],
}).compileComponents();
}));
diff --git a/apps/frontend/src/app/app.component.ts b/apps/frontend/src/app/app.component.ts
index a5ef2d16..26ac5b17 100644
--- a/apps/frontend/src/app/app.component.ts
+++ b/apps/frontend/src/app/app.component.ts
@@ -3,21 +3,30 @@ import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
selector: 'fe-root',
template: `
-
-
-
-
+
-
- Right
-
+
+
+
+
+
-
-
-
-
+
+ Right
+
+
+
+
+
+
+
+
+
`,
changeDetection: ChangeDetectionStrategy.OnPush,
+ styleUrls: ['./app.component.scss'],
})
export class AppComponent {
title = 'frontend';
diff --git a/apps/frontend/src/app/app.module.ts b/apps/frontend/src/app/app.module.ts
index 58db50bd..72df9030 100644
--- a/apps/frontend/src/app/app.module.ts
+++ b/apps/frontend/src/app/app.module.ts
@@ -4,12 +4,14 @@ import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import { RouterModule } from '@angular/router';
import { EffectsModule } from '@ngrx/effects';
import { StoreModule } from '@ngrx/store';
-import { SidenavShellModule } from '@talus/ui';
+import { UiSidenavShellModule } from '@talus/ui';
import { AppComponent } from './app.component';
import { AppEffects } from './app.effects';
import { metaReducers, ROOT_REDUCERS } from './app.reducer';
+import { MenuBarContainerModule } from './menu-bar-container/menu-bar-container.module';
import { SceneViewerContainerModule } from './scene-viewer-container';
import { ToolsPanelModule } from './tools-panel/tools-panel.module';
+import { UndoRedoModule } from './undo-redo/undo-redo.module';
@NgModule({
declarations: [AppComponent],
@@ -35,9 +37,11 @@ import { ToolsPanelModule } from './tools-panel/tools-panel.module';
},
}),
+ MenuBarContainerModule,
SceneViewerContainerModule,
- SidenavShellModule,
+ UiSidenavShellModule,
ToolsPanelModule,
+ UndoRedoModule,
],
providers: [],
bootstrap: [AppComponent],
diff --git a/apps/frontend/src/app/app.reducer.ts b/apps/frontend/src/app/app.reducer.ts
index 82ec8af7..4c401a18 100644
--- a/apps/frontend/src/app/app.reducer.ts
+++ b/apps/frontend/src/app/app.reducer.ts
@@ -10,8 +10,10 @@ import {
import { environment } from '../environments/environment';
import * as fromSceneViewerContainer from './scene-viewer-container/scene-viewer-container.reducer';
import * as fromToolsPanel from './tools-panel/tools-panel.reducer';
+import * as fromUndoRedo from './undo-redo/undo-redo.reducer';
export interface State {
+ [fromUndoRedo.featureKey]: fromUndoRedo.State;
[fromToolsPanel.featureKey]: fromToolsPanel.State;
[fromSceneViewerContainer.featureKey]: fromSceneViewerContainer.State;
}
@@ -27,8 +29,9 @@ export const ROOT_REDUCERS = new InjectionToken>
'Root reducers token',
{
factory: () => ({
- [fromToolsPanel.featureKey]: fromToolsPanel.reducer,
[fromSceneViewerContainer.featureKey]: fromSceneViewerContainer.reducer,
+ [fromToolsPanel.featureKey]: fromToolsPanel.reducer,
+ [fromUndoRedo.featureKey]: fromUndoRedo.reducer,
}),
},
);
@@ -78,3 +81,30 @@ export const selectSelectedToolId = createSelector(
selectToolsPanelState,
fromToolsPanel.selectSelectedToolId,
);
+
+/**
+ * UndoRedo reducers
+ */
+export const selectUndoRedoState = createFeatureSelector(
+ fromUndoRedo.featureKey,
+);
+
+export const selectCurrentUndoStartAction = createSelector(
+ selectUndoRedoState,
+ fromUndoRedo.selectCurrentUndoStartAction,
+);
+
+export const selectCurrentRedoStartAction = createSelector(
+ selectUndoRedoState,
+ fromUndoRedo.selectCurrentRedoStartAction,
+);
+
+export const selectCurrentUndoEndAction = createSelector(
+ selectUndoRedoState,
+ fromUndoRedo.selectCurrentUndoEndAction,
+);
+
+export const selectCurrentRedoEndAction = createSelector(
+ selectUndoRedoState,
+ fromUndoRedo.selectCurrentRedoEndAction,
+);
diff --git a/apps/frontend/src/app/menu-bar-container/menu-bar-container.actions.ts b/apps/frontend/src/app/menu-bar-container/menu-bar-container.actions.ts
new file mode 100644
index 00000000..04d964a2
--- /dev/null
+++ b/apps/frontend/src/app/menu-bar-container/menu-bar-container.actions.ts
@@ -0,0 +1,6 @@
+import { createAction } from '@ngrx/store';
+
+const actionTypePrefix = `[menuBarContainer]`;
+
+export const undo = createAction(`${actionTypePrefix} Undo`);
+export const redo = createAction(`${actionTypePrefix} Redo`);
diff --git a/apps/frontend/src/app/menu-bar-container/menu-bar-container.component.spec.ts b/apps/frontend/src/app/menu-bar-container/menu-bar-container.component.spec.ts
new file mode 100644
index 00000000..b8bc23ba
--- /dev/null
+++ b/apps/frontend/src/app/menu-bar-container/menu-bar-container.component.spec.ts
@@ -0,0 +1,53 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { Store, StoreModule } from '@ngrx/store';
+import { MockStore } from '@ngrx/store/testing';
+import { ROOT_REDUCERS, State } from '../app.reducer';
+import { undo } from './menu-bar-container.actions';
+import { MenuBarContainerComponent } from './menu-bar-container.component';
+import { MenuBarContainerModule } from './menu-bar-container.module';
+
+describe('MenuBarComponent', () => {
+ let component: MenuBarContainerComponent;
+ let fixture: ComponentFixture;
+
+ let store: MockStore;
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ declarations: [],
+ imports: [
+ MenuBarContainerModule,
+ StoreModule.forRoot(ROOT_REDUCERS, {
+ runtimeChecks: {
+ strictStateImmutability: true,
+ strictActionImmutability: true,
+ strictStateSerializability: true,
+ strictActionSerializability: true,
+ },
+ }),
+ ],
+ }).compileComponents();
+
+ store = TestBed.get>(Store);
+ }));
+
+ beforeEach(() => {
+ spyOn(store, 'dispatch');
+ });
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(MenuBarContainerComponent);
+ component = fixture.componentInstance;
+ fixture.detectChanges();
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should dispatch action', () => {
+ component.onMenuItemClick(undo());
+
+ expect(store.dispatch).toHaveBeenCalledWith(undo());
+ });
+});
diff --git a/apps/frontend/src/app/menu-bar-container/menu-bar-container.component.ts b/apps/frontend/src/app/menu-bar-container/menu-bar-container.component.ts
new file mode 100644
index 00000000..a2e76188
--- /dev/null
+++ b/apps/frontend/src/app/menu-bar-container/menu-bar-container.component.ts
@@ -0,0 +1,40 @@
+import { ChangeDetectionStrategy, Component } from '@angular/core';
+import { Action, Store } from '@ngrx/store';
+import { UiMenuBarConfig } from '@talus/ui';
+import * as fromApp from '../app.reducer';
+import { redo, undo } from './menu-bar-container.actions';
+
+@Component({
+ selector: 'fe-menu-bar-container',
+ template: `
+
+ `,
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class MenuBarContainerComponent {
+ menuConfig: UiMenuBarConfig = {
+ menus: [
+ {
+ label: 'Edit',
+ menuItems: [
+ {
+ icon: 'undo',
+ label: 'Undo',
+ value: undo(),
+ },
+ {
+ icon: 'redo',
+ label: 'Redo',
+ value: redo(),
+ },
+ ],
+ },
+ ],
+ };
+
+ constructor(private store: Store) {}
+
+ onMenuItemClick(action: Action): void {
+ this.store.dispatch(action);
+ }
+}
diff --git a/apps/frontend/src/app/menu-bar-container/menu-bar-container.module.ts b/apps/frontend/src/app/menu-bar-container/menu-bar-container.module.ts
new file mode 100644
index 00000000..2347c696
--- /dev/null
+++ b/apps/frontend/src/app/menu-bar-container/menu-bar-container.module.ts
@@ -0,0 +1,10 @@
+import { NgModule } from '@angular/core';
+import { UiMenuBarModule } from '@talus/ui';
+import { MenuBarContainerComponent } from './menu-bar-container.component';
+
+@NgModule({
+ declarations: [MenuBarContainerComponent],
+ imports: [UiMenuBarModule],
+ exports: [MenuBarContainerComponent],
+})
+export class MenuBarContainerModule {}
diff --git a/apps/frontend/src/app/scene-viewer-container/grid.service.ts b/apps/frontend/src/app/scene-viewer-container/grid.service.ts
index 4b2d47c9..4fda072e 100644
--- a/apps/frontend/src/app/scene-viewer-container/grid.service.ts
+++ b/apps/frontend/src/app/scene-viewer-container/grid.service.ts
@@ -1,5 +1,5 @@
import { Injectable } from '@angular/core';
-import { Coord, Grid, gridToMesh, MeshData } from '@talus/vdb';
+import { Coord, Grid, MeshData, nodeToMesh } from '@talus/vdb';
/**
* Keeps the mutable state of the single grid. This state is not part of the store, due to
@@ -12,15 +12,73 @@ export class GridService {
grid = new Grid(0);
accessor = this.grid.getAccessor();
- addVoxel(xyz: Coord, value: number): void {
- this.accessor.setValue(xyz, value);
+ colors = {
+ 0: [0, 0, 0, 1],
+ 1: [0, 0, 1, 1],
+ 2: [0, 1, 0, 1],
+ 3: [0, 1, 1, 1],
+ 4: [1, 0, 0, 1],
+ 5: [1, 0, 1, 1],
+ 6: [1, 1, 0, 1],
+ 7: [1, 1, 1, 1],
+ };
+
+ /**
+ * Adds a new voxel via accessor to share access path.
+ * @returns origin of `InternalNode1` of affected node (node containing added voxel).
+ */
+ addVoxel(xyz: Coord, value: number): VoxelChange {
+ this.accessor.setValueOn(xyz, value);
+
+ return {
+ affectedNodeOrigin: this.accessor.internalNode1Origin,
+ value,
+ position: xyz,
+ };
}
- removeVoxel(xyz: Coord): void {
- this.accessor.setValueOff(xyz, this.grid.background);
+ addVoxels(coords: Coord[], values: number[]): VoxelChange[] {
+ const changes = new Map();
+
+ if (coords.length !== values.length) {
+ throw new Error(`Coordinates and values don't have the same length.`);
+ }
+
+ coords.forEach((xyz, i) => {
+ const change = this.addVoxel(xyz, values[i]);
+ changes.set(change.affectedNodeOrigin.toString(), change);
+ });
+
+ return Array.from(changes.values());
}
- computeMesh(): MeshData | undefined {
- return gridToMesh(this.grid);
+ removeVoxel(xyz: Coord): VoxelChange {
+ this.accessor.setActiveState(xyz, false);
+
+ return {
+ affectedNodeOrigin: this.accessor.internalNode1Origin,
+ value: this.accessor.getValue(xyz),
+ position: xyz,
+ };
}
+
+ computeInternalNode1Mesh(origin: Coord): MeshData | undefined {
+ const internal1 = this.accessor.probeInternalNode1(origin);
+
+ if (!internal1) {
+ return undefined;
+ }
+
+ return nodeToMesh(internal1, this.valueToColor);
+ }
+
+ private valueToColor = (value: number): [number, number, number, number] => {
+ return this.colors[value % 8];
+ };
+}
+
+export interface VoxelChange {
+ affectedNodeOrigin: Coord;
+ value: number;
+ position: Coord;
}
diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts
index d8f32abc..5154e280 100644
--- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts
+++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.actions.ts
@@ -1,18 +1,29 @@
import { createAction, props } from '@ngrx/store';
import { Coord } from '@talus/vdb';
+import { VoxelChange } from './grid.service';
-const actionTypePrefix = '[SceneViewerContainer]';
+const actionTypePrefix = `[sceneViewerContainer]`;
export const addVoxel = createAction(
`${actionTypePrefix} Add voxel`,
props<{ position: Coord; value: number }>(),
);
export const addVoxelFailed = createAction(`${actionTypePrefix} Add voxel failed`);
-export const voxelAdded = createAction(`${actionTypePrefix} Voxel added`);
+export const voxelAdded = createAction(`${actionTypePrefix} Voxel added`, props());
+
+export const addVoxels = createAction(
+ `${actionTypePrefix} Add voxels`,
+ props<{ positions: Coord[]; values: number[] }>(),
+);
+export const addVoxelsFailed = createAction(`${actionTypePrefix} Add voxels failed`);
+export const voxelsAdded = createAction(
+ `${actionTypePrefix} Voxels added`,
+ props<{ voxelChanges: VoxelChange[] }>(),
+);
export const removeVoxel = createAction(
`${actionTypePrefix} Remove voxel`,
props<{ position: Coord }>(),
);
export const removeVoxelFailed = createAction(`${actionTypePrefix} Remove voxel failed`);
-export const voxelRemoved = createAction(`${actionTypePrefix} Voxel removed`);
+export const voxelRemoved = createAction(`${actionTypePrefix} Voxel removed`, props());
diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.spec.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.spec.ts
index cc914e18..d3da561d 100644
--- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.spec.ts
+++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.spec.ts
@@ -3,7 +3,7 @@ import { async, ComponentFixture, TestBed } from '@angular/core/testing';
import { By } from '@angular/platform-browser';
import { MemoizedSelector, Store } from '@ngrx/store';
import { MockStore, provideMockStore } from '@ngrx/store/testing';
-import { PointerButton, PointerPickInfo } from '@talus/ui';
+import { UiPointerButton, UiPointerPickInfo } from '@talus/ui';
import { Coord } from '@talus/vdb';
import { Subject } from 'rxjs';
import * as fromApp from '../app.reducer';
@@ -18,7 +18,7 @@ import { SceneViewerContainerComponent } from './scene-viewer-container.componen
changeDetection: ChangeDetectionStrategy.OnPush,
})
class SceneViewerStubComponent {
- @Output() pointerPick = new Subject();
+ @Output() pointerPick = new Subject();
}
describe('SceneViewerContainerComponent', () => {
@@ -36,7 +36,6 @@ describe('SceneViewerContainerComponent', () => {
}).compileComponents();
mockStore = TestBed.get(Store);
- spyOn(mockStore, 'dispatch');
mockSelectedToolIdSelector = mockStore.overrideSelector(
fromApp.selectSelectedToolId,
@@ -44,6 +43,10 @@ describe('SceneViewerContainerComponent', () => {
);
}));
+ beforeEach(async(() => {
+ spyOn(mockStore, 'dispatch');
+ }));
+
beforeEach(() => {
fixture = TestBed.createComponent(SceneViewerContainerComponent);
component = fixture.componentInstance;
@@ -62,11 +65,12 @@ describe('SceneViewerContainerComponent', () => {
it('should dispatch no action if not PointerButton.Main', () => {
stubComponent.pointerPick.next({
pickedPoint: [0, 0, 0],
- pointerButton: PointerButton.Secondary,
+ pointerButton: UiPointerButton.Secondary,
normal: [0, 0, 0],
});
- expect(mockStore.dispatch).not.toHaveBeenCalled();
+ // Only once called due to first initial added voxel at [0, 0, 0]
+ expect(mockStore.dispatch).toHaveBeenCalledTimes(1);
});
it.each([
@@ -113,14 +117,16 @@ describe('SceneViewerContainerComponent', () => {
])(
'should dispatch `addVoxel` action for %j',
(pickedPoint: Coord, position: Coord, normal: Coord) => {
- const action = addVoxel({ position, value: 42 });
+ const initialAction = addVoxel({ position: [0, 0, 0], value: 42 });
+ const action = addVoxel({ position, value: 1 });
stubComponent.pointerPick.next({
pickedPoint,
- pointerButton: PointerButton.Main,
+ pointerButton: UiPointerButton.Main,
normal,
});
+ expect(mockStore.dispatch).toHaveBeenCalledWith(initialAction);
expect(mockStore.dispatch).toHaveBeenCalledWith(action);
},
);
@@ -172,7 +178,7 @@ describe('SceneViewerContainerComponent', () => {
stubComponent.pointerPick.next({
pickedPoint,
- pointerButton: PointerButton.Main,
+ pointerButton: UiPointerButton.Main,
normal,
});
diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.ts
index d9efee4c..179cbf63 100644
--- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.ts
+++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.component.ts
@@ -1,8 +1,8 @@
-import { ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
+import { AfterViewInit, ChangeDetectionStrategy, Component, ViewChild } from '@angular/core';
// import '@babylonjs/core/Rendering/edgesRenderer';
// import '@babylonjs/core/Rendering/outlineRenderer';
import { select, Store } from '@ngrx/store';
-import { PointerButton, PointerPickInfo, SceneViewerComponent } from '@talus/ui';
+import { UiPointerButton, UiPointerPickInfo, UiSceneViewerComponent } from '@talus/ui';
import { Coord } from '@talus/vdb';
import { Observable } from 'rxjs';
import * as fromApp from '../app.reducer';
@@ -19,16 +19,20 @@ import { addVoxel, removeVoxel } from './scene-viewer-container.actions';
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class SceneViewerContainerComponent {
- @ViewChild(SceneViewerComponent, { static: false })
- private sceneViewerComponent: SceneViewerComponent;
+export class SceneViewerContainerComponent implements AfterViewInit {
+ @ViewChild(UiSceneViewerComponent, { static: false })
+ private sceneViewerComponent: UiSceneViewerComponent;
selectedToolId$: Observable = this.store.pipe(select(fromApp.selectSelectedToolId));
voxelCount$: Observable = this.store.pipe(select(fromApp.selectVoxelCount));
constructor(private store: Store) {}
- onPointerPick(event: PointerPickInfo, selectedToolId: Tool): void {
+ ngAfterViewInit(): void {
+ this.store.dispatch(addVoxel({ position: [0, 0, 0], value: 42 }));
+ }
+
+ onPointerPick(event: UiPointerPickInfo, selectedToolId: Tool): void {
this.dispatchPickAction(event, selectedToolId);
}
@@ -37,15 +41,15 @@ export class SceneViewerContainerComponent {
// mesh.renderOutline = !mesh.renderOutline;
// }
- private dispatchPickAction(pickInfo: PointerPickInfo, selectedToolId: Tool): void {
- if (pickInfo.pointerButton !== PointerButton.Main) {
+ private dispatchPickAction(pickInfo: UiPointerPickInfo, selectedToolId: Tool): void {
+ if (pickInfo.pointerButton !== UiPointerButton.Main) {
return;
}
switch (selectedToolId) {
case Tool.AddVoxel:
this.store.dispatch(
- addVoxel({ position: this.calcVoxelToAddPosition(pickInfo), value: 42 }),
+ addVoxel({ position: this.calcVoxelToAddPosition(pickInfo), value: 1 }),
);
break;
case Tool.RemoveVoxel:
@@ -54,7 +58,7 @@ export class SceneViewerContainerComponent {
}
}
- private calcVoxelToAddPosition(pickInfo: PointerPickInfo): Coord {
+ private calcVoxelToAddPosition(pickInfo: UiPointerPickInfo): Coord {
const pickedIntegerPoint = this.roundDimensionAlongNormal(pickInfo);
// VDB removes fractional-part of the coordinate, i.e. 0.54 -> 0.
@@ -76,7 +80,7 @@ export class SceneViewerContainerComponent {
return newPoint;
}
- private calcVoxelToRemovePosition(pickInfo: PointerPickInfo): Coord {
+ private calcVoxelToRemovePosition(pickInfo: UiPointerPickInfo): Coord {
const pickedIntegerPoint = this.roundDimensionAlongNormal(pickInfo);
const newPoint: Coord = [
@@ -103,7 +107,7 @@ export class SceneViewerContainerComponent {
* Since all the voxels are placed on integer positions the dimension of the picked point
* needs to be rounded.
*/
- private roundDimensionAlongNormal(pickInfo: PointerPickInfo): Coord {
+ private roundDimensionAlongNormal(pickInfo: UiPointerPickInfo): Coord {
return [
pickInfo.normal[0] !== 0 ? Math.round(pickInfo.pickedPoint[0]) : pickInfo.pickedPoint[0],
pickInfo.normal[1] !== 0 ? Math.round(pickInfo.pickedPoint[1]) : pickInfo.pickedPoint[1],
diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts
index 20571c6c..03c7fe79 100644
--- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts
+++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.effects.ts
@@ -1,16 +1,20 @@
import { Injectable } from '@angular/core';
import { Actions, createEffect, ofType } from '@ngrx/effects';
-import { SceneViewerService } from '@talus/ui';
+import { UiSceneViewerService } from '@talus/ui';
+import { Coord } from '@talus/vdb';
import { of } from 'rxjs';
-import { catchError, map, tap } from 'rxjs/operators';
+import { catchError, map } from 'rxjs/operators';
import { GridService } from './grid.service';
import {
addVoxel,
addVoxelFailed,
+ addVoxels,
+ addVoxelsFailed,
removeVoxel,
removeVoxelFailed,
voxelAdded,
voxelRemoved,
+ voxelsAdded,
} from './scene-viewer-container.actions';
@Injectable()
@@ -18,34 +22,60 @@ export class SceneViewerContainerEffects {
constructor(
private actions$: Actions,
private gridService: GridService,
- private sceneViewerService: SceneViewerService,
+ private sceneViewerService: UiSceneViewerService,
) {}
addVoxel$ = createEffect(() =>
this.actions$.pipe(
ofType(addVoxel),
- tap({
- next: ({ position, value }) => {
- this.gridService.addVoxel(position, value);
- this.sceneViewerService.updateGridMesh(this.gridService.computeMesh());
- },
- }),
- map(() => voxelAdded()),
+ map(({ position, value }) => this.gridService.addVoxel(position, value)),
+ map(voxelAdded),
catchError(() => of(addVoxelFailed())),
),
);
+ addVoxels$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(addVoxels),
+ map(({ positions, values }) => this.gridService.addVoxels(positions, values)),
+ map(voxelChanges => voxelsAdded({ voxelChanges })),
+ catchError(() => of(addVoxelsFailed())),
+ ),
+ );
+
removeVoxel$ = createEffect(() =>
this.actions$.pipe(
ofType(removeVoxel),
- tap({
- next: ({ position }) => {
- this.gridService.removeVoxel(position);
- this.sceneViewerService.updateGridMesh(this.gridService.computeMesh());
- },
- }),
- map(() => voxelRemoved()),
+ map(({ position }) => this.gridService.removeVoxel(position)),
+ map(voxelRemoved),
catchError(() => of(removeVoxelFailed())),
),
);
+
+ updateGridMesh$ = createEffect(
+ () =>
+ this.actions$.pipe(
+ ofType(voxelAdded, voxelRemoved),
+ map(({ affectedNodeOrigin }) => this.computeAndUpdateNodeMesh(affectedNodeOrigin)),
+ ),
+ { dispatch: false },
+ );
+
+ updateGridMeshMultiple$ = createEffect(
+ () =>
+ this.actions$.pipe(
+ ofType(voxelsAdded),
+ map(({ voxelChanges }) =>
+ voxelChanges.map(change => {
+ this.computeAndUpdateNodeMesh(change.affectedNodeOrigin);
+ }),
+ ),
+ ),
+ { dispatch: false },
+ );
+
+ private computeAndUpdateNodeMesh(affectedNodeOrigin: Coord): void {
+ const mesh = this.gridService.computeInternalNode1Mesh(affectedNodeOrigin);
+ this.sceneViewerService.updateNodeMesh(mesh, affectedNodeOrigin);
+ }
}
diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.module.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.module.ts
index ac65b3af..2c2622fe 100644
--- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.module.ts
+++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.module.ts
@@ -1,7 +1,7 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { EffectsModule } from '@ngrx/effects';
-import { SceneViewerModule } from '@talus/ui';
+import { UiSceneViewerModule } from '@talus/ui';
import { GridService } from './grid.service';
import { SceneViewerContainerComponent } from './scene-viewer-container.component';
import { SceneViewerContainerEffects } from './scene-viewer-container.effects';
@@ -11,7 +11,7 @@ import { SceneViewerContainerEffects } from './scene-viewer-container.effects';
imports: [
CommonModule,
EffectsModule.forFeature([SceneViewerContainerEffects]),
- SceneViewerModule,
+ UiSceneViewerModule,
],
exports: [SceneViewerContainerComponent],
providers: [GridService],
diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.spec.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.spec.ts
new file mode 100644
index 00000000..b8f51290
--- /dev/null
+++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.spec.ts
@@ -0,0 +1,30 @@
+import { VoxelChange } from './grid.service';
+import { voxelAdded, voxelRemoved } from './scene-viewer-container.actions';
+import { reducer, selectVoxelCount } from './scene-viewer-container.reducer';
+
+describe('SceneViewerContainerReducer', () => {
+ const voxelChange: VoxelChange = {
+ position: [0, 0, 0],
+ affectedNodeOrigin: [0, 0, 0],
+ value: 42,
+ };
+
+ it('should increment counter', () => {
+ const stateWithOneVoxel = reducer(undefined, voxelAdded(voxelChange));
+
+ expect(stateWithOneVoxel.voxelCount).toEqual(1);
+ });
+
+ it('should decrement counter', () => {
+ const stateWithOneVoxel = reducer(undefined, voxelAdded(voxelChange));
+ const stateWithNoVoxel = reducer(stateWithOneVoxel, voxelRemoved(voxelChange));
+
+ expect(stateWithNoVoxel.voxelCount).toEqual(0);
+ });
+
+ it('should select voxel count', () => {
+ const stateWithOneVoxel = reducer(undefined, voxelAdded(voxelChange));
+
+ expect(selectVoxelCount(stateWithOneVoxel)).toEqual(1);
+ });
+});
diff --git a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts
index f89ac931..1b8ea98b 100644
--- a/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts
+++ b/apps/frontend/src/app/scene-viewer-container/scene-viewer-container.reducer.ts
@@ -1,5 +1,5 @@
import { createReducer, on } from '@ngrx/store';
-import { voxelAdded } from './scene-viewer-container.actions';
+import { voxelAdded, voxelRemoved } from './scene-viewer-container.actions';
export const featureKey = 'sceneViewerContainer';
@@ -19,6 +19,12 @@ export const reducer = createReducer(
voxelCount: state.voxelCount + 1,
};
}),
+ on(voxelRemoved, state => {
+ return {
+ ...state,
+ voxelCount: state.voxelCount - 1,
+ };
+ }),
);
export const selectVoxelCount = (state: State) => state.voxelCount;
diff --git a/apps/frontend/src/app/tools-panel/tools-panel.actions.ts b/apps/frontend/src/app/tools-panel/tools-panel.actions.ts
index 308ce61b..1827a91b 100644
--- a/apps/frontend/src/app/tools-panel/tools-panel.actions.ts
+++ b/apps/frontend/src/app/tools-panel/tools-panel.actions.ts
@@ -1,4 +1,4 @@
import { createAction, props } from '@ngrx/store';
import { Tool } from './tool.model';
-export const selectTool = createAction('[ToolsPanel] Select tool', props<{ id: Tool }>());
+export const selectTool = createAction('[toolsPanel] Select tool', props<{ id: Tool }>());
diff --git a/apps/frontend/src/app/tools-panel/tools-panel.module.ts b/apps/frontend/src/app/tools-panel/tools-panel.module.ts
index 55db8f76..fc96800f 100644
--- a/apps/frontend/src/app/tools-panel/tools-panel.module.ts
+++ b/apps/frontend/src/app/tools-panel/tools-panel.module.ts
@@ -1,11 +1,11 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
-import { ToolbarModule } from '@talus/ui';
+import { UiToolbarModule } from '@talus/ui';
import { ToolsPanelComponent } from './tools-panel.component';
@NgModule({
declarations: [ToolsPanelComponent],
- imports: [CommonModule, ToolbarModule],
+ imports: [CommonModule, UiToolbarModule],
exports: [ToolsPanelComponent],
})
export class ToolsPanelModule {}
diff --git a/apps/frontend/src/app/tools-panel/tools-panel.reducer.spec.ts b/apps/frontend/src/app/tools-panel/tools-panel.reducer.spec.ts
new file mode 100644
index 00000000..48409661
--- /dev/null
+++ b/apps/frontend/src/app/tools-panel/tools-panel.reducer.spec.ts
@@ -0,0 +1,11 @@
+import { Tool } from './tool.model';
+import { selectTool } from './tools-panel.actions';
+import { reducer } from './tools-panel.reducer';
+
+describe('ToolsPanelReducer', () => {
+ it('should set selected tool', () => {
+ const newState = reducer(undefined, selectTool({ id: Tool.AddVoxel }));
+
+ expect(newState.selectedToolId).toEqual(Tool.AddVoxel);
+ });
+});
diff --git a/apps/frontend/src/app/undo-redo/undo-redo.actions.ts b/apps/frontend/src/app/undo-redo/undo-redo.actions.ts
new file mode 100644
index 00000000..a797592b
--- /dev/null
+++ b/apps/frontend/src/app/undo-redo/undo-redo.actions.ts
@@ -0,0 +1,26 @@
+import { Action, createAction, props } from '@ngrx/store';
+
+const actionTypePrefix = `[undoRedo]`;
+
+export const addUndo = createAction(
+ `${actionTypePrefix} Add undo`,
+ props<{
+ redoStartAction: Action;
+ redoEndActionType: string;
+ undoStartAction: Action;
+ undoEndActionType: string;
+ }>(),
+);
+
+export const undo = createAction(`${actionTypePrefix} Undo`);
+
+export const undone = createAction(`${actionTypePrefix} Undone`);
+
+export const addRedo = createAction(
+ `${actionTypePrefix} Add redo`,
+ props<{ redoAction: Action }>(),
+);
+
+export const redo = createAction(`${actionTypePrefix} Redo`);
+
+export const redone = createAction(`${actionTypePrefix} Redone`);
diff --git a/apps/frontend/src/app/undo-redo/undo-redo.effects.ts b/apps/frontend/src/app/undo-redo/undo-redo.effects.ts
new file mode 100644
index 00000000..4bafbe85
--- /dev/null
+++ b/apps/frontend/src/app/undo-redo/undo-redo.effects.ts
@@ -0,0 +1,98 @@
+import { Injectable } from '@angular/core';
+import { Actions, createEffect, ofType } from '@ngrx/effects';
+import { select, Store } from '@ngrx/store';
+import { filter, map, switchMap, withLatestFrom } from 'rxjs/operators';
+import * as fromApp from '../app.reducer';
+import * as menuBarContainerActions from '../menu-bar-container/menu-bar-container.actions';
+import {
+ addVoxel,
+ removeVoxel,
+ voxelAdded,
+ voxelRemoved,
+} from '../scene-viewer-container/scene-viewer-container.actions';
+import { addUndo, redo, redone, undo, undone } from './undo-redo.actions';
+
+@Injectable()
+export class UndoRedoEffects {
+ constructor(private actions$: Actions, private store: Store) {}
+
+ undo$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(undo, menuBarContainerActions.undo),
+ withLatestFrom(this.store.pipe(select(fromApp.selectCurrentUndoStartAction))),
+ switchMap(([action, currentUndoAction]) =>
+ currentUndoAction ? [currentUndoAction] : [undone()],
+ ),
+ ),
+ );
+
+ redo$ = createEffect(() =>
+ this.actions$.pipe(
+ ofType(redo, menuBarContainerActions.redo),
+ withLatestFrom(this.store.pipe(select(fromApp.selectCurrentRedoStartAction))),
+ switchMap(([action, currentRedoAction]) =>
+ currentRedoAction ? [currentRedoAction] : [redone()],
+ ),
+ ),
+ );
+
+ undoTriggeredActions$ = this.actions$.pipe(
+ withLatestFrom(this.store.pipe(select(fromApp.selectUndoRedoState))),
+ filter(([action, state]) => state.isUndoing),
+ map(([action, state]) => action),
+ );
+
+ undone$ = createEffect(() =>
+ this.undoTriggeredActions$.pipe(
+ withLatestFrom(this.store.pipe(select(fromApp.selectCurrentUndoEndAction))),
+ filter(([action, undoEndAction]) => action.type === undoEndAction),
+ map(() => undone()),
+ ),
+ );
+
+ redoTriggeredActions$ = this.actions$.pipe(
+ withLatestFrom(this.store.pipe(select(fromApp.selectUndoRedoState))),
+ filter(([action, state]) => state.isRedoing),
+ map(([action, state]) => action),
+ );
+
+ redone$ = createEffect(() =>
+ this.redoTriggeredActions$.pipe(
+ withLatestFrom(this.store.pipe(select(fromApp.selectCurrentRedoEndAction))),
+ filter(([action, redoEndAction]) => action.type === redoEndAction),
+ map(() => redone()),
+ ),
+ );
+
+ userTriggeredActions$ = this.actions$.pipe(
+ withLatestFrom(this.store.pipe(select(fromApp.selectUndoRedoState))),
+ filter(([action, state]) => !state.isUndoing && !state.isRedoing),
+ map(([action, state]) => action),
+ );
+
+ addUndoActionForAddVoxel$ = createEffect(() =>
+ this.userTriggeredActions$.pipe(
+ ofType(voxelAdded),
+ map(voxelChange => ({
+ redoStartAction: addVoxel(voxelChange),
+ redoEndActionType: voxelAdded.type,
+ undoStartAction: removeVoxel({ position: voxelChange.position }),
+ undoEndActionType: voxelRemoved.type,
+ })),
+ map(addUndo),
+ ),
+ );
+
+ addUndoActionForRemoveVoxel$ = createEffect(() =>
+ this.userTriggeredActions$.pipe(
+ ofType(voxelRemoved),
+ map(voxelChange => ({
+ redoStartAction: removeVoxel({ position: voxelChange.position }),
+ redoEndActionType: voxelRemoved.type,
+ undoStartAction: addVoxel(voxelChange),
+ undoEndActionType: voxelAdded.type,
+ })),
+ map(addUndo),
+ ),
+ );
+}
diff --git a/apps/frontend/src/app/undo-redo/undo-redo.module.ts b/apps/frontend/src/app/undo-redo/undo-redo.module.ts
new file mode 100644
index 00000000..7dd160d4
--- /dev/null
+++ b/apps/frontend/src/app/undo-redo/undo-redo.module.ts
@@ -0,0 +1,8 @@
+import { NgModule } from '@angular/core';
+import { EffectsModule } from '@ngrx/effects';
+import { UndoRedoEffects } from './undo-redo.effects';
+
+@NgModule({
+ imports: [EffectsModule.forFeature([UndoRedoEffects])],
+})
+export class UndoRedoModule {}
diff --git a/apps/frontend/src/app/undo-redo/undo-redo.reducer.spec.ts b/apps/frontend/src/app/undo-redo/undo-redo.reducer.spec.ts
new file mode 100644
index 00000000..61afc316
--- /dev/null
+++ b/apps/frontend/src/app/undo-redo/undo-redo.reducer.spec.ts
@@ -0,0 +1,199 @@
+import { Action } from '@ngrx/store';
+import { Coord } from '@talus/vdb';
+import { VoxelChange } from '../scene-viewer-container/grid.service';
+import {
+ addVoxel,
+ removeVoxel,
+ voxelAdded,
+ voxelRemoved,
+} from '../scene-viewer-container/scene-viewer-container.actions';
+import { addUndo, redo, redone, undo, undone } from './undo-redo.actions';
+import {
+ reducer,
+ selectCurrentRedoEndAction,
+ selectCurrentRedoStartAction,
+ selectCurrentUndoEndAction,
+ selectCurrentUndoStartAction,
+ State,
+} from './undo-redo.reducer';
+
+describe('UndoRedoReducer', () => {
+ const voxelChange0 = createVoxelChange([0, 0, 0]);
+ const step0 = createStep(voxelChange0);
+ const voxelChange1 = createVoxelChange([1, 1, 1]);
+ const step1 = createStep(voxelChange1);
+ const voxelChange2 = createVoxelChange([2, 2, 2]);
+ const step2 = createStep(voxelChange2);
+
+ it('should be undoing', () => {
+ const newState = reducer(undefined, undo());
+
+ expect(newState.isUndoing).toEqual(true);
+ });
+
+ it('should be redoing', () => {
+ const newState = reducer(undefined, redo());
+
+ expect(newState.isRedoing).toEqual(true);
+ });
+
+ it('should add undo step', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+
+ expectActionLengthToEqual(newState, 3);
+ });
+
+ it('should update current index', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+
+ expect(newState.currentIndex).toEqual(2);
+ expectActionLengthToEqual(newState, 3);
+ });
+
+ it('should select current undo/redo', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+
+ expect(selectCurrentUndoStartAction(newState)).toEqual(step2.undoStartAction);
+ expect(selectCurrentUndoEndAction(newState)).toEqual(step2.undoEndActionType);
+ expect(selectCurrentRedoStartAction(newState)).toBeUndefined();
+ expect(selectCurrentRedoEndAction(newState)).toBeUndefined();
+ });
+
+ it('should select current undo/redo after one undone', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+ newState = reducer(newState, undone());
+
+ expect(newState.currentIndex).toEqual(1);
+ expectActionLengthToEqual(newState, 3);
+
+ expect(selectCurrentUndoStartAction(newState)).toEqual(step1.undoStartAction);
+ expect(selectCurrentUndoEndAction(newState)).toEqual(step1.undoEndActionType);
+ expect(selectCurrentRedoStartAction(newState)).toEqual(step2.redoStartAction);
+ expect(selectCurrentRedoEndAction(newState)).toEqual(step2.redoEndActionType);
+ });
+
+ it('should select current undo/redo after three undone & one redo', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, redone());
+
+ expect(newState.currentIndex).toEqual(0);
+ expectActionLengthToEqual(newState, 3);
+
+ expect(selectCurrentUndoStartAction(newState)).toEqual(step0.undoStartAction);
+ expect(selectCurrentUndoEndAction(newState)).toEqual(step0.undoEndActionType);
+ expect(selectCurrentRedoStartAction(newState)).toEqual(step1.redoStartAction);
+ expect(selectCurrentRedoEndAction(newState)).toEqual(step1.redoEndActionType);
+ });
+
+ it('should consider max buffer size of 10', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+ newState = reducer(newState, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+ newState = reducer(newState, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+ newState = reducer(newState, addUndo(step0));
+
+ newState = reducer(newState, addUndo(step1));
+
+ expect(newState.currentIndex).toEqual(9);
+ expectActionLengthToEqual(newState, 10);
+ });
+
+ it('should remove history', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step0));
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, addUndo(step2));
+
+ expect(newState.currentIndex).toEqual(4);
+ expectActionLengthToEqual(newState, 5);
+ });
+
+ it('should stop decrement index after too many undo', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+
+ newState = reducer(newState, undone());
+
+ expect(newState.currentIndex).toEqual(-1);
+ expectActionLengthToEqual(newState, 3);
+ });
+
+ it('should stop increment index after too many redo', () => {
+ let newState = reducer(undefined, addUndo(step0));
+ newState = reducer(newState, addUndo(step1));
+ newState = reducer(newState, addUndo(step2));
+ newState = reducer(newState, undone());
+ newState = reducer(newState, undone());
+ newState = reducer(newState, redone());
+ newState = reducer(newState, redone());
+
+ newState = reducer(newState, redone());
+
+ expect(newState.currentIndex).toEqual(2);
+ expectActionLengthToEqual(newState, 3);
+ });
+});
+
+function createVoxelChange(xyz: Coord): VoxelChange {
+ return {
+ position: xyz,
+ affectedNodeOrigin: xyz,
+ value: 42,
+ };
+}
+
+function createStep(
+ voxelChange: VoxelChange,
+): {
+ redoEndActionType: string;
+ redoStartAction: Action;
+ undoEndActionType: string;
+ undoStartAction: Action;
+} {
+ return {
+ redoStartAction: addVoxel(voxelChange),
+ redoEndActionType: voxelAdded.type,
+ undoStartAction: removeVoxel({ position: voxelChange.position }),
+ undoEndActionType: voxelRemoved.type,
+ };
+}
+
+function expectActionLengthToEqual(state: State, length: number): void {
+ expect(state.redoStartActions.length).toEqual(length);
+ expect(state.redoEndActionTypes.length).toEqual(length);
+ expect(state.undoStartActions.length).toEqual(length);
+ expect(state.undoEndActionTypes.length).toEqual(length);
+}
diff --git a/apps/frontend/src/app/undo-redo/undo-redo.reducer.ts b/apps/frontend/src/app/undo-redo/undo-redo.reducer.ts
new file mode 100644
index 00000000..565251e3
--- /dev/null
+++ b/apps/frontend/src/app/undo-redo/undo-redo.reducer.ts
@@ -0,0 +1,103 @@
+import { Action, createReducer, on } from '@ngrx/store';
+import * as menuBarContainerActions from '../menu-bar-container/menu-bar-container.actions';
+import { addUndo, redo, redone, undo, undone } from './undo-redo.actions';
+
+/**
+ * Use normal reducer instead of meta-reducer, to have the state in the normal store
+ * and therefore accessible (e.g. for display in app the number of redo actions).
+ * Also use normal effects to run/replay/dispatch the action to be undone.
+ */
+
+export const featureKey = 'undoRedo';
+
+export interface State {
+ currentIndex: number;
+ isRedoing: boolean;
+ isUndoing: boolean;
+ redoEndActionTypes: string[];
+ redoStartActions: Action[];
+ undoEndActionTypes: string[];
+ undoStartActions: Action[];
+}
+
+export const initialState: State = {
+ currentIndex: -1,
+ isRedoing: false,
+ isUndoing: false,
+ redoEndActionTypes: [],
+ redoStartActions: [],
+ undoEndActionTypes: [],
+ undoStartActions: [],
+};
+
+const maxBufferSize = 10;
+const maxBufferIndex = maxBufferSize - 1;
+
+export const reducer = createReducer(
+ initialState,
+
+ on(
+ addUndo,
+ (state, { redoStartAction, redoEndActionType, undoStartAction, undoEndActionType }) => {
+ const newIndex = state.currentIndex + 1;
+
+ const redoStartActions = state.redoStartActions.slice(0, newIndex);
+ const redoEndActionTypes = state.redoEndActionTypes.slice(0, newIndex);
+ const undoStartActions = state.undoStartActions.slice(0, newIndex);
+ const undoEndActionTypes = state.undoEndActionTypes.slice(0, newIndex);
+
+ return {
+ ...state,
+ currentIndex: newIndex > maxBufferIndex ? maxBufferIndex : newIndex,
+ redoStartActions: [...redoStartActions.slice(-maxBufferIndex), redoStartAction],
+ redoEndActionTypes: [...redoEndActionTypes.slice(-maxBufferIndex), redoEndActionType],
+ undoStartActions: [...undoStartActions.slice(-maxBufferIndex), undoStartAction],
+ undoEndActionTypes: [...undoEndActionTypes.slice(-maxBufferIndex), undoEndActionType],
+ };
+ },
+ ),
+
+ on(undo, menuBarContainerActions.undo, state => {
+ return {
+ ...state,
+ isUndoing: true,
+ };
+ }),
+
+ on(redo, menuBarContainerActions.redo, state => {
+ return {
+ ...state,
+ isRedoing: true,
+ };
+ }),
+
+ on(undone, state => {
+ const newIndex = state.currentIndex - 1;
+
+ return {
+ ...state,
+ isUndoing: false,
+ currentIndex: newIndex < 0 ? -1 : newIndex,
+ };
+ }),
+
+ on(redone, state => {
+ const newIndex = state.currentIndex + 1;
+ const maxRedoIndex = state.redoStartActions.length - 1;
+
+ return {
+ ...state,
+ isRedoing: false,
+ currentIndex: newIndex > maxRedoIndex ? maxRedoIndex : newIndex,
+ };
+ }),
+);
+
+export const selectCurrentRedoStartAction = (state: State) =>
+ state.redoStartActions[state.currentIndex + 1];
+export const selectCurrentRedoEndAction = (state: State) =>
+ state.redoEndActionTypes[state.currentIndex + 1];
+export const selectCurrentUndoStartAction = (state: State) =>
+ state.undoStartActions[state.currentIndex];
+export const selectCurrentUndoEndAction = (state: State) =>
+ state.undoEndActionTypes[state.currentIndex];
diff --git a/libs/ui/jest.config.js b/libs/ui/jest.config.js
index 35d35ffa..b2ed4000 100644
--- a/libs/ui/jest.config.js
+++ b/libs/ui/jest.config.js
@@ -21,11 +21,11 @@ module.exports = {
],
// https://github.com/nrwl/nx/issues/1439#issuecomment-561268656
// When using `Run test` directly in WebStorm, change the used config to
- // this file i.e. `./ui/jest.config.js` and not `/jest.config.js`.
+ // this file i.e. `./ui/jest.config.js` and not `/jest.config.js`.
// Otherwise, following error might occur:
// - Cannot find module '@talus/ui'
// - Zone is needed for the async() test helper but could not be found.
- setupFilesAfterEnv: ['./src/test-setup.ts'],
+ setupFilesAfterEnv: ['/src/test-setup.ts'],
// https://github.com/thymikee/jest-preset-angular/issues/293#issuecomment-513544717
// When using `Run test` directly in WebStorm, the scss couldn't be loaded.
diff --git a/libs/ui/src/index.ts b/libs/ui/src/index.ts
index 03119d04..5793e9fa 100644
--- a/libs/ui/src/index.ts
+++ b/libs/ui/src/index.ts
@@ -1,4 +1,5 @@
-export * from './lib/ui.module';
-export * from './lib/sidenav-shell';
+export * from './lib/menu-bar';
export * from './lib/scene-viewer';
+export * from './lib/sidenav-shell';
export * from './lib/toolbar';
+export * from './lib/ui.module';
diff --git a/libs/ui/src/lib/menu-bar/index.ts b/libs/ui/src/lib/menu-bar/index.ts
new file mode 100644
index 00000000..3a658a8f
--- /dev/null
+++ b/libs/ui/src/lib/menu-bar/index.ts
@@ -0,0 +1,2 @@
+export * from './menu-bar.component';
+export * from './menu-bar.module';
diff --git a/libs/ui/src/lib/menu-bar/menu-bar.component.scss b/libs/ui/src/lib/menu-bar/menu-bar.component.scss
new file mode 100644
index 00000000..22da7177
--- /dev/null
+++ b/libs/ui/src/lib/menu-bar/menu-bar.component.scss
@@ -0,0 +1,5 @@
+$angular-button-height: 36px;
+
+mat-toolbar {
+ height: $angular-button-height;
+}
diff --git a/libs/ui/src/lib/menu-bar/menu-bar.component.spec.ts b/libs/ui/src/lib/menu-bar/menu-bar.component.spec.ts
new file mode 100644
index 00000000..7f709fc2
--- /dev/null
+++ b/libs/ui/src/lib/menu-bar/menu-bar.component.spec.ts
@@ -0,0 +1,112 @@
+import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { By } from '@angular/platform-browser';
+import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
+import { UiMenuBarModule } from '@talus/ui';
+import { UiMenuBarComponent } from './menu-bar.component';
+
+describe('UiMenuBarComponent', () => {
+ let component: UiMenuBarComponent;
+ let fixture: ComponentFixture;
+
+ const expectedMenus = [
+ {
+ label: 'Menu 1',
+ menuItems: [
+ {
+ label: 'Item 1.1',
+ icon: 'undo',
+ value: 'Value 1.1',
+ },
+ ],
+ },
+ {
+ label: 'Menu 2',
+ menuItems: [
+ {
+ label: 'Item 2.1',
+ icon: 'undo',
+ value: 'Value 2.1',
+ },
+ {
+ label: 'Item 2.2',
+ icon: 'undo',
+ value: 'Value 2.2',
+ },
+ ],
+ },
+ ];
+
+ beforeEach(async(() => {
+ TestBed.configureTestingModule({
+ imports: [UiMenuBarModule, BrowserAnimationsModule],
+ }).compileComponents();
+ }));
+
+ beforeEach(() => {
+ fixture = TestBed.createComponent(UiMenuBarComponent);
+ component = fixture.componentInstance;
+ // Don't call `detectChanges()`, because of `OnPush`
+ // See: https://github.com/angular/angular/issues/12313#issuecomment-301848232
+ // fixture.detectChanges();
+ });
+
+ beforeEach(() => {
+ spyOn(component.menuItemClick, 'emit');
+ });
+
+ it('should create', () => {
+ expect(component).toBeTruthy();
+ });
+
+ it('should add all menus', () => {
+ component.menuConfig = {
+ menus: expectedMenus,
+ };
+ fixture.detectChanges();
+
+ const menus = fixture.debugElement.queryAll(By.css('mat-menu'));
+ const menuButtons = fixture.debugElement.queryAll(By.css('button'));
+
+ expect(menus.length).toEqual(expectedMenus.length);
+ expect(menuButtons.length).toEqual(expectedMenus.length);
+ expect(menuButtons[0].nativeElement.textContent).toContain(expectedMenus[0].label);
+ expect(menuButtons[1].nativeElement.textContent).toContain(expectedMenus[1].label);
+ });
+
+ it('should add all menu-items for second menu', () => {
+ component.menuConfig = {
+ menus: expectedMenus,
+ };
+ fixture.detectChanges();
+
+ const menuButtons = fixture.debugElement.queryAll(By.css('button'));
+ menuButtons[1].nativeElement.click();
+ fixture.detectChanges();
+
+ const menuItemButtons = fixture.debugElement.queryAll(By.css('button.mat-menu-item > span'));
+ expect(menuItemButtons.length).toEqual(expectedMenus[1].menuItems.length);
+
+ menuItemButtons.forEach((menuItemButton, j) => {
+ expect(menuItemButton.nativeElement.textContent).toEqual(expectedMenus[1].menuItems[j].label);
+ });
+ });
+
+ it('should emit value of clicked menu items', () => {
+ component.menuConfig = {
+ menus: expectedMenus,
+ };
+ fixture.detectChanges();
+
+ const menuButtons = fixture.debugElement.queryAll(By.css('button'));
+ menuButtons[1].nativeElement.click();
+ fixture.detectChanges();
+
+ const menuItemButtons = fixture.debugElement.queryAll(By.css('button.mat-menu-item > span'));
+
+ menuItemButtons[0].nativeElement.click();
+ expect(component.menuItemClick.emit).toBeCalledWith('Value 2.1');
+
+ menuItemButtons[1].nativeElement.click();
+ expect(component.menuItemClick.emit).toBeCalledWith('Value 2.2');
+ });
+});
diff --git a/libs/ui/src/lib/menu-bar/menu-bar.component.ts b/libs/ui/src/lib/menu-bar/menu-bar.component.ts
new file mode 100644
index 00000000..010b1e28
--- /dev/null
+++ b/libs/ui/src/lib/menu-bar/menu-bar.component.ts
@@ -0,0 +1,48 @@
+import { ChangeDetectionStrategy, Component, EventEmitter, Input, Output } from '@angular/core';
+
+export interface UiMenuBarConfig {
+ menus: UiMenuBarMenu[];
+}
+
+interface UiMenuBarMenu {
+ label: string;
+ menuItems: UiMenuBarMenuItem[];
+}
+
+interface UiMenuBarMenuItem {
+ icon?: string;
+ label: string;
+ value: T;
+}
+
+@Component({
+ selector: 'ui-menu-bar',
+ template: `
+
+
+
+
+
+
+
+
+ `,
+ styleUrls: ['./menu-bar.component.scss'],
+ changeDetection: ChangeDetectionStrategy.OnPush,
+})
+export class UiMenuBarComponent {
+ @Input() menuConfig: UiMenuBarConfig = { menus: [] };
+
+ @Output() menuItemClick = new EventEmitter();
+
+ onMenuItemClick(value: any): void {
+ this.menuItemClick.emit(value);
+ }
+}
diff --git a/libs/ui/src/lib/menu-bar/menu-bar.module.ts b/libs/ui/src/lib/menu-bar/menu-bar.module.ts
new file mode 100644
index 00000000..cff9cb92
--- /dev/null
+++ b/libs/ui/src/lib/menu-bar/menu-bar.module.ts
@@ -0,0 +1,11 @@
+import { CommonModule } from '@angular/common';
+import { NgModule } from '@angular/core';
+import { MatButtonModule, MatIconModule, MatMenuModule, MatToolbarModule } from '@angular/material';
+import { UiMenuBarComponent } from './menu-bar.component';
+
+@NgModule({
+ declarations: [UiMenuBarComponent],
+ imports: [CommonModule, MatButtonModule, MatIconModule, MatMenuModule, MatToolbarModule],
+ exports: [UiMenuBarComponent],
+})
+export class UiMenuBarModule {}
diff --git a/libs/ui/src/lib/scene-viewer/index.ts b/libs/ui/src/lib/scene-viewer/index.ts
index 14b12407..7dfea1ff 100644
--- a/libs/ui/src/lib/scene-viewer/index.ts
+++ b/libs/ui/src/lib/scene-viewer/index.ts
@@ -1,5 +1,5 @@
export * from './scene-viewer.component';
export * from './scene-viewer.module';
export * from './scene-viewer.module.testing';
-export { PointerButton } from './pointer-button';
-export { PointerPickInfo, SceneViewerService } from './scene-viewer.service';
+export { UiPointerButton } from './pointer-button';
+export { UiPointerPickInfo, UiSceneViewerService } from './scene-viewer.service';
diff --git a/libs/ui/src/lib/scene-viewer/pointer-button.ts b/libs/ui/src/lib/scene-viewer/pointer-button.ts
index 39afd4c3..f5ca1d33 100644
--- a/libs/ui/src/lib/scene-viewer/pointer-button.ts
+++ b/libs/ui/src/lib/scene-viewer/pointer-button.ts
@@ -1,7 +1,7 @@
/**
* https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button#Syntax
*/
-export enum PointerButton {
+export enum UiPointerButton {
Main = 0, // usually the left button or the un-initialized state
Auxiliary = 1, // usually the wheel button or the middle button (if present)
Secondary = 2, // usually the right button
diff --git a/libs/ui/src/lib/scene-viewer/scene-viewer.component.scss b/libs/ui/src/lib/scene-viewer/scene-viewer.component.scss
index 519ffd16..5a6bfab9 100644
--- a/libs/ui/src/lib/scene-viewer/scene-viewer.component.scss
+++ b/libs/ui/src/lib/scene-viewer/scene-viewer.component.scss
@@ -1,6 +1,4 @@
-:host,
canvas {
- display: block;
- width: 100%;
height: 100%;
+ width: 100%;
}
diff --git a/libs/ui/src/lib/scene-viewer/scene-viewer.component.spec.ts b/libs/ui/src/lib/scene-viewer/scene-viewer.component.spec.ts
index b9ae1951..abc1db3f 100644
--- a/libs/ui/src/lib/scene-viewer/scene-viewer.component.spec.ts
+++ b/libs/ui/src/lib/scene-viewer/scene-viewer.component.spec.ts
@@ -1,20 +1,20 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { SceneViewerComponent } from './scene-viewer.component';
-import { SceneViewerTestModule } from './scene-viewer.module.testing';
+import { UiSceneViewerComponent } from './scene-viewer.component';
+import { UiSceneViewerTestModule } from './scene-viewer.module.testing';
-describe('SceneViewerComponent', () => {
- let component: SceneViewerComponent;
- let fixture: ComponentFixture;
+describe('UiSceneViewerComponent', () => {
+ let component: UiSceneViewerComponent;
+ let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
- declarations: [SceneViewerComponent],
- imports: [SceneViewerTestModule],
+ declarations: [UiSceneViewerComponent],
+ imports: [UiSceneViewerTestModule],
}).compileComponents();
}));
beforeEach(() => {
- fixture = TestBed.createComponent(SceneViewerComponent);
+ fixture = TestBed.createComponent(UiSceneViewerComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
diff --git a/libs/ui/src/lib/scene-viewer/scene-viewer.component.ts b/libs/ui/src/lib/scene-viewer/scene-viewer.component.ts
index 6c5538ae..58e40fcd 100644
--- a/libs/ui/src/lib/scene-viewer/scene-viewer.component.ts
+++ b/libs/ui/src/lib/scene-viewer/scene-viewer.component.ts
@@ -2,35 +2,94 @@ import {
ChangeDetectionStrategy,
Component,
ElementRef,
+ EventEmitter,
HostListener,
OnInit,
Output,
ViewChild,
} from '@angular/core';
-import { SceneViewerService } from './scene-viewer.service';
+import { UiSceneViewerService } from './scene-viewer.service';
@Component({
selector: 'ui-scene-viewer',
template: `
-
+
`,
styleUrls: ['./scene-viewer.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class SceneViewerComponent implements OnInit {
+export class UiSceneViewerComponent implements OnInit {
+ constructor(private sceneViewerService: UiSceneViewerService) {}
+
@ViewChild('canvas', { static: true }) canvas: ElementRef;
@Output() pointerPick = this.sceneViewerService.pointerPick$;
- constructor(private sceneViewerService: SceneViewerService) {}
+ @Output() dropFiles = new EventEmitter();
+
+ ngOnInit(): void {
+ this.sceneViewerService.initialize(this.canvas.nativeElement);
+ this.sceneViewerService.startRendering();
+ }
@HostListener('window:resize')
onWindowsResize(): void {
this.sceneViewerService.resizeView();
}
- ngOnInit(): void {
- this.sceneViewerService.initialize(this.canvas.nativeElement);
- this.sceneViewerService.startRendering();
+ onDragOver(event: DragEvent): void {
+ // Prevent file from being opened
+ event.preventDefault();
+ }
+
+ onDrop(event: DragEvent): void {
+ // Prevent file from being opened
+ event.preventDefault();
+
+ this.dropFiles.emit(this.getFiles(event));
+ }
+
+ // Source: https://developer.mozilla.org/en-US/docs/Web/API/HTML_Drag_and_Drop_API/File_drag_and_drop
+ private getFiles(event: DragEvent): File[] {
+ return event.dataTransfer && event.dataTransfer.items
+ ? this.getFilesFromDataTransferItemList(event)
+ : this.getFilesFromDataTransfer(event);
+ }
+
+ private getFilesFromDataTransferItemList(event: DragEvent): File[] {
+ const files: File[] = [];
+
+ if (!event.dataTransfer) {
+ return files;
+ }
+
+ // Use DataTransferItemList interface to access the file(s)
+ for (let i = 0; i < event.dataTransfer.items.length; i++) {
+ // If dropped items aren't files, reject them
+ if (event.dataTransfer.items[i].kind === 'file') {
+ const file = event.dataTransfer.items[i].getAsFile();
+
+ if (file) {
+ files.push(file);
+ }
+ }
+ }
+
+ return files;
+ }
+
+ private getFilesFromDataTransfer(event: DragEvent): File[] {
+ const files: File[] = [];
+
+ if (!event.dataTransfer) {
+ return files;
+ }
+
+ // Use DataTransfer interface to access the file(s)
+ for (let i = 0; i < event.dataTransfer.files.length; i++) {
+ files.push(event.dataTransfer.files[i]);
+ }
+
+ return files;
}
}
diff --git a/libs/ui/src/lib/scene-viewer/scene-viewer.module.testing.ts b/libs/ui/src/lib/scene-viewer/scene-viewer.module.testing.ts
index e5b28056..10527d82 100644
--- a/libs/ui/src/lib/scene-viewer/scene-viewer.module.testing.ts
+++ b/libs/ui/src/lib/scene-viewer/scene-viewer.module.testing.ts
@@ -4,7 +4,7 @@ import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera';
import { NullEngine } from '@babylonjs/core/Engines/nullEngine';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
import { Scene } from '@babylonjs/core/scene';
-import { CameraFactory, EngineFactory, SceneViewerService } from './scene-viewer.service';
+import { CameraFactory, EngineFactory, UiSceneViewerService } from './scene-viewer.service';
function testCameraFactory(): any {
return {
@@ -47,16 +47,16 @@ function testEngineFactor(): any {
template: ``,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class SceneViewerStubComponent {}
+export class UiSceneViewerStubComponent {}
@NgModule({
- declarations: [SceneViewerStubComponent],
- exports: [SceneViewerStubComponent],
+ declarations: [UiSceneViewerStubComponent],
+ exports: [UiSceneViewerStubComponent],
imports: [CommonModule],
providers: [
{ provide: CameraFactory, useValue: testCameraFactory() },
{ provide: EngineFactory, useValue: testEngineFactor() },
- SceneViewerService,
+ UiSceneViewerService,
],
})
-export class SceneViewerTestModule {}
+export class UiSceneViewerTestModule {}
diff --git a/libs/ui/src/lib/scene-viewer/scene-viewer.module.ts b/libs/ui/src/lib/scene-viewer/scene-viewer.module.ts
index c569b163..cf093c83 100644
--- a/libs/ui/src/lib/scene-viewer/scene-viewer.module.ts
+++ b/libs/ui/src/lib/scene-viewer/scene-viewer.module.ts
@@ -1,12 +1,12 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
-import { SceneViewerComponent } from './scene-viewer.component';
-import { CameraFactory, EngineFactory, SceneViewerService } from './scene-viewer.service';
+import { UiSceneViewerComponent } from './scene-viewer.component';
+import { CameraFactory, EngineFactory, UiSceneViewerService } from './scene-viewer.service';
@NgModule({
- declarations: [SceneViewerComponent],
+ declarations: [UiSceneViewerComponent],
imports: [CommonModule],
- exports: [SceneViewerComponent],
- providers: [CameraFactory, EngineFactory, SceneViewerService],
+ exports: [UiSceneViewerComponent],
+ providers: [CameraFactory, EngineFactory, UiSceneViewerService],
})
-export class SceneViewerModule {}
+export class UiSceneViewerModule {}
diff --git a/libs/ui/src/lib/scene-viewer/scene-viewer.service.ts b/libs/ui/src/lib/scene-viewer/scene-viewer.service.ts
index 1ffeb152..5dfeb749 100644
--- a/libs/ui/src/lib/scene-viewer/scene-viewer.service.ts
+++ b/libs/ui/src/lib/scene-viewer/scene-viewer.service.ts
@@ -1,4 +1,5 @@
import { Injectable } from '@angular/core';
+import { AbstractMesh } from '@babylonjs/core';
// Babylon.js needs to target individual files to fully benefit from tree shaking.
// See: https://doc.babylonjs.com/features/es6_support#tree-shaking
import { ArcRotateCamera } from '@babylonjs/core/Cameras/arcRotateCamera';
@@ -7,14 +8,15 @@ import { Engine } from '@babylonjs/core/Engines/engine';
import { HemisphericLight } from '@babylonjs/core/Lights/hemisphericLight';
import '@babylonjs/core/Materials/standardMaterial';
import { Vector3 } from '@babylonjs/core/Maths/math.vector';
+import { VertexBuffer } from '@babylonjs/core/Meshes/buffer';
import { Mesh } from '@babylonjs/core/Meshes/mesh';
import { VertexData } from '@babylonjs/core/Meshes/mesh.vertexData';
-import { MeshBuilder } from '@babylonjs/core/Meshes/meshBuilder';
+import { TransformNode } from '@babylonjs/core/Meshes/transformNode';
import '@babylonjs/core/Physics/physicsHelper'; // Needed for `onPointerPick`
import { Scene } from '@babylonjs/core/scene';
import { Coord, MeshData } from '@talus/vdb';
import { Subject } from 'rxjs';
-import { PointerButton } from './pointer-button';
+import { UiPointerButton } from './pointer-button';
@Injectable()
export class EngineFactory {
@@ -51,13 +53,12 @@ export class CameraFactory {
* provided on module level. Therefore, only one `SceneViewerComponent` at the time is supported.
*/
@Injectable()
-export class SceneViewerService {
- scene: Scene;
- gridMesh: Mesh;
-
- pointerPick$ = new Subject();
+export class UiSceneViewerService {
+ pointerPick$ = new Subject();
private engine: Engine;
+ private scene: Scene;
+ private gridNode: TransformNode;
// @ts-ignore: noUnusedLocals
private light: HemisphericLight;
@@ -65,17 +66,11 @@ export class SceneViewerService {
initialize(canvas: HTMLCanvasElement): void {
this.engine = this.engineFactory.create(canvas);
- this.scene = new Scene(this.engine);
-
+ this.createScene();
this.createCamera();
this.createLight();
this.registerPointerPick();
-
- const box = MeshBuilder.CreateBox('box', {}, this.scene);
- box.position.x = 0.5;
- box.position.y = 0.5;
- box.position.z = 0.5;
}
startRendering(): void {
@@ -86,22 +81,43 @@ export class SceneViewerService {
this.engine.resize();
}
- updateGridMesh(mesh?: MeshData): void {
- this.scene.removeMesh(this.gridMesh);
+ updateNodeMesh(mesh: MeshData | undefined, origin: Coord): void {
+ const meshName = `node1 [${origin}]`;
+
+ this.deleteMesh(meshName);
if (mesh) {
- this.gridMesh = new Mesh('grid', this.scene);
const data = new VertexData();
+ const nodeMesh = new Mesh(meshName, this.scene, this.gridNode);
+ // https://www.html5gamedevs.com/topic/31617-mesh-without-indices/?tab=comments#comment-181659
+ // https://doc.babylonjs.com/how_to/optimizing_your_scene#using-unindexed-meshes
+ nodeMesh._unIndexed = true;
data.colors = mesh.colors;
- data.indices = mesh.indices;
+ data.normals = mesh.normals;
data.positions = mesh.positions;
- data.applyToMesh(this.gridMesh);
- this.gridMesh.convertToFlatShadedMesh();
+ data.applyToMesh(nodeMesh);
+
+ // https://doc.babylonjs.com/how_to/optimizing_your_scene
+ // https://www.html5gamedevs.com/topic/12504-performancedraw-calls/
+ nodeMesh.freezeNormals();
+ nodeMesh.freezeWorldMatrix();
}
}
+ private createScene(): void {
+ // https://doc.babylonjs.com/how_to/optimizing_your_scene
+ this.scene = new Scene(this.engine, {
+ useGeometryUniqueIdsMap: true,
+ useClonedMeshMap: true,
+ });
+ this.scene.freezeMaterials();
+
+ // Used only as parent to have all nodes grouped together
+ this.gridNode = new TransformNode('grid', this.scene);
+ }
+
private createCamera(): void {
const camera: ArcRotateCamera = this.cameraFactory.create(
'camera',
@@ -113,12 +129,16 @@ export class SceneViewerService {
);
camera.inertia = 0;
camera.panningInertia = 0;
+ camera.wheelPrecision = 1.0;
- camera.panningSensibility = 20;
+ camera.panningSensibility = 10;
camera.angularSensibilityX = 200;
camera.angularSensibilityY = 100;
- camera.attachControl(this.engine.getRenderingCanvas(), true, false, 2);
+ const renderingCanvas = this.engine.getRenderingCanvas();
+ if (renderingCanvas) {
+ camera.attachControl(renderingCanvas, true, false, 2);
+ }
camera.setPosition(new Vector3(20, 20, -20));
}
@@ -128,23 +148,51 @@ export class SceneViewerService {
private registerPointerPick(): void {
this.scene.onPointerPick = (event: PointerEvent, pickInfo: PickingInfo): void => {
- const info: PointerPickInfo = {
- pickedPoint: vector3ToCoord(pickInfo.pickedPoint),
- pointerButton: event.button,
- normal: vector3ToCoord(pickInfo.getNormal()),
- };
-
- this.pointerPick$.next(info);
+ if (pickInfo.pickedMesh && pickInfo.pickedPoint) {
+ const info: UiPointerPickInfo = {
+ pickedPoint: vector3ToCoord(pickInfo.pickedPoint),
+ pointerButton: event.button,
+ normal: this.getNormal(pickInfo.pickedMesh, pickInfo.faceId),
+ };
+
+ this.pointerPick$.next(info);
+ }
};
}
+
+ /**
+ * PickingInfo.getNormal() requires to have indices which are not available
+ * for an un-indexed custom mesh. Therefore, read normals directly from picked mesh.
+ *
+ * https://github.com/BabylonJS/Babylon.js/blob/master/src/Collisions/pickingInfo.ts#L65
+ */
+ private getNormal(pickedMesh: AbstractMesh, faceId: number): Coord {
+ const normals = pickedMesh.getVerticesData(VertexBuffer.NormalKind);
+
+ if (!normals) {
+ throw new Error('Could not get normals from picked mesh.');
+ }
+
+ const faceIndex = faceId * 9;
+
+ return [normals[faceIndex], normals[faceIndex + 1], normals[faceIndex + 2]];
+ }
+
+ private deleteMesh(name: string): void {
+ const oldMesh = this.scene.getMeshByName(name);
+
+ if (oldMesh) {
+ oldMesh.dispose();
+ }
+ }
}
function vector3ToCoord(vector: Vector3): Coord {
return [vector.x, vector.y, vector.z];
}
-export interface PointerPickInfo {
+export interface UiPointerPickInfo {
pickedPoint: Coord;
- pointerButton: PointerButton;
+ pointerButton: UiPointerButton;
normal: Coord;
}
diff --git a/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.scss b/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.scss
index dbc3fea8..62b77cef 100644
--- a/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.scss
+++ b/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.scss
@@ -1,6 +1,5 @@
:host,
mat-sidenav-container {
- display: block;
height: 100%;
}
diff --git a/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.spec.ts b/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.spec.ts
index 3d684bf3..464b0862 100644
--- a/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.spec.ts
+++ b/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.spec.ts
@@ -1,21 +1,23 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
+import { MatSidenav } from '@angular/material';
+import { By } from '@angular/platform-browser';
-import { SidenavShellComponent } from './sidenav-shell.component';
-import { SidenavShellModule } from './sidenav-shell.module';
+import { UiSidenavShellComponent } from './sidenav-shell.component';
+import { UiSidenavShellModule } from './sidenav-shell.module';
describe('SidenavShellComponent', () => {
- let component: SidenavShellComponent;
- let fixture: ComponentFixture;
+ let component: UiSidenavShellComponent;
+ let fixture: ComponentFixture;
beforeEach(async(() => {
TestBed.configureTestingModule({
- imports: [SidenavShellModule],
+ imports: [UiSidenavShellModule],
declarations: [],
}).compileComponents();
}));
beforeEach(() => {
- fixture = TestBed.createComponent(SidenavShellComponent);
+ fixture = TestBed.createComponent(UiSidenavShellComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
@@ -23,4 +25,32 @@ describe('SidenavShellComponent', () => {
it('should create', () => {
expect(component).toBeTruthy();
});
+
+ it('should have open left & right sidenav', () => {
+ const sidenavs = fixture.debugElement.queryAll(By.directive(MatSidenav));
+ const leftSidenavIcon = fixture.debugElement.query(By.css('#left-sidenav-button mat-icon'));
+ const rightSidenavIcon = fixture.debugElement.query(By.css('#right-sidenav-button mat-icon'));
+
+ expect(sidenavs.length).toEqual(2);
+ expect(leftSidenavIcon.nativeElement.textContent).toEqual('keyboard_arrow_left');
+ expect(rightSidenavIcon.nativeElement.textContent).toEqual('keyboard_arrow_right');
+ });
+
+ it('should close left & right sidenav', () => {
+ // Close left sidenav
+ const leftSidenavButton = fixture.debugElement.query(By.css('#left-sidenav-button'));
+ leftSidenavButton.nativeElement.click();
+ fixture.detectChanges();
+
+ const leftIconClosed = fixture.debugElement.query(By.css('#left-sidenav-button mat-icon'));
+ expect(leftIconClosed.nativeElement.textContent).toEqual('keyboard_arrow_right');
+
+ // Close right sidenav
+ const rightSidenavButton = fixture.debugElement.query(By.css('#right-sidenav-button'));
+ rightSidenavButton.nativeElement.click();
+ fixture.detectChanges();
+
+ const rightIconClosed = fixture.debugElement.query(By.css('#right-sidenav-button mat-icon'));
+ expect(rightIconClosed.nativeElement.textContent).toEqual('keyboard_arrow_left');
+ });
});
diff --git a/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.ts b/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.ts
index bc22de2f..d4087cfa 100644
--- a/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.ts
+++ b/libs/ui/src/lib/sidenav-shell/sidenav-shell.component.ts
@@ -1,4 +1,4 @@
-import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
+import { ChangeDetectionStrategy, Component } from '@angular/core';
@Component({
selector: 'ui-sidenav-shell-content',
@@ -7,7 +7,7 @@ import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core';
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class SidenavShellContentComponent {}
+export class UiSidenavShellContentComponent {}
@Component({
selector: 'ui-sidenav-shell-left',
@@ -16,7 +16,7 @@ export class SidenavShellContentComponent {}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class SidenavShellLeftComponent {}
+export class UiSidenavShellLeftComponent {}
@Component({
selector: 'ui-sidenav-shell-right',
@@ -25,7 +25,7 @@ export class SidenavShellLeftComponent {}
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class SidenavShellRightComponent {}
+export class UiSidenavShellRightComponent {}
@Component({
selector: 'ui-sidenav-shell',
@@ -57,8 +57,4 @@ export class SidenavShellRightComponent {}
styleUrls: ['./sidenav-shell.component.scss'],
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class SidenavShellComponent implements OnInit {
- constructor() {}
-
- public ngOnInit(): void {}
-}
+export class UiSidenavShellComponent {}
diff --git a/libs/ui/src/lib/sidenav-shell/sidenav-shell.module.ts b/libs/ui/src/lib/sidenav-shell/sidenav-shell.module.ts
index 0486da5c..50a11df6 100644
--- a/libs/ui/src/lib/sidenav-shell/sidenav-shell.module.ts
+++ b/libs/ui/src/lib/sidenav-shell/sidenav-shell.module.ts
@@ -3,18 +3,18 @@ import { NgModule } from '@angular/core';
import { MatButtonModule, MatIconModule, MatSidenavModule } from '@angular/material';
import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
import {
- SidenavShellComponent,
- SidenavShellContentComponent,
- SidenavShellLeftComponent,
- SidenavShellRightComponent,
+ UiSidenavShellComponent,
+ UiSidenavShellContentComponent,
+ UiSidenavShellLeftComponent,
+ UiSidenavShellRightComponent,
} from './sidenav-shell.component';
@NgModule({
declarations: [
- SidenavShellComponent,
- SidenavShellContentComponent,
- SidenavShellLeftComponent,
- SidenavShellRightComponent,
+ UiSidenavShellComponent,
+ UiSidenavShellContentComponent,
+ UiSidenavShellLeftComponent,
+ UiSidenavShellRightComponent,
],
imports: [
BrowserAnimationsModule,
@@ -24,10 +24,10 @@ import {
MatSidenavModule,
],
exports: [
- SidenavShellComponent,
- SidenavShellContentComponent,
- SidenavShellLeftComponent,
- SidenavShellRightComponent,
+ UiSidenavShellComponent,
+ UiSidenavShellContentComponent,
+ UiSidenavShellLeftComponent,
+ UiSidenavShellRightComponent,
],
})
-export class SidenavShellModule {}
+export class UiSidenavShellModule {}
diff --git a/libs/ui/src/lib/toolbar/toolbar.component.spec.ts b/libs/ui/src/lib/toolbar/toolbar.component.spec.ts
index 3d0b3276..c605ef2a 100644
--- a/libs/ui/src/lib/toolbar/toolbar.component.spec.ts
+++ b/libs/ui/src/lib/toolbar/toolbar.component.spec.ts
@@ -1,24 +1,55 @@
import { async, ComponentFixture, TestBed } from '@angular/core/testing';
-import { ToolbarComponent } from './toolbar.component';
-import { ToolbarModule } from './toolbar.module';
+import { By } from '@angular/platform-browser';
+import { UiToolbarComponent, UiToolbarToolConfig } from './toolbar.component';
+import { UiToolbarModule } from './toolbar.module';
describe('ToolbarComponent', () => {
- let component: ToolbarComponent;
- let fixture: ComponentFixture;
+ let component: UiToolbarComponent;
+ let fixture: ComponentFixture;
+
+ const tools: UiToolbarToolConfig[] = [
+ {
+ icon: 'add_circle_outline',
+ tooltip: 'Add',
+ value: 'Add test value',
+ },
+ {
+ icon: 'remove_circle_outline',
+ tooltip: 'Remove',
+ value: 'Remove test value',
+ },
+ ];
beforeEach(async(() => {
TestBed.configureTestingModule({
- imports: [ToolbarModule],
+ imports: [UiToolbarModule],
}).compileComponents();
}));
beforeEach(() => {
- fixture = TestBed.createComponent(ToolbarComponent);
+ fixture = TestBed.createComponent(UiToolbarComponent);
component = fixture.componentInstance;
- fixture.detectChanges();
+ // fixture.detectChanges();
+ });
+
+ beforeEach(() => {
+ spyOn(component.toolChange, 'emit');
});
it('should create', () => {
expect(component).toBeTruthy();
});
+
+ it('should emit tool change', () => {
+ component.tools = tools;
+ fixture.detectChanges();
+
+ const buttonToggles = fixture.debugElement.queryAll(By.css('button.mat-button-toggle-button'));
+ expect(buttonToggles.length).toEqual(tools.length);
+
+ buttonToggles[0].nativeElement.click();
+ fixture.detectChanges();
+
+ expect(component.toolChange.emit).toHaveBeenCalled();
+ });
});
diff --git a/libs/ui/src/lib/toolbar/toolbar.component.ts b/libs/ui/src/lib/toolbar/toolbar.component.ts
index 68e2f341..d18e85c9 100644
--- a/libs/ui/src/lib/toolbar/toolbar.component.ts
+++ b/libs/ui/src/lib/toolbar/toolbar.component.ts
@@ -28,7 +28,7 @@ export interface UiToolbarToolChange extends MatButtonToggleChange {
`,
changeDetection: ChangeDetectionStrategy.OnPush,
})
-export class ToolbarComponent {
+export class UiToolbarComponent {
@Input() tools: UiToolbarToolConfig[];
@Input() selectedToolId: any;
diff --git a/libs/ui/src/lib/toolbar/toolbar.module.ts b/libs/ui/src/lib/toolbar/toolbar.module.ts
index 6e77b28c..5e5bbd0f 100644
--- a/libs/ui/src/lib/toolbar/toolbar.module.ts
+++ b/libs/ui/src/lib/toolbar/toolbar.module.ts
@@ -1,11 +1,11 @@
import { CommonModule } from '@angular/common';
import { NgModule } from '@angular/core';
import { MatButtonToggleModule, MatIconModule, MatTooltipModule } from '@angular/material';
-import { ToolbarComponent } from './toolbar.component';
+import { UiToolbarComponent } from './toolbar.component';
@NgModule({
- declarations: [ToolbarComponent],
+ declarations: [UiToolbarComponent],
imports: [CommonModule, MatButtonToggleModule, MatIconModule, MatTooltipModule],
- exports: [ToolbarComponent],
+ exports: [UiToolbarComponent],
})
-export class ToolbarModule {}
+export class UiToolbarModule {}
diff --git a/libs/ui/src/test-setup.ts b/libs/ui/src/test-setup.ts
index 8d88704e..26ec1bb0 100644
--- a/libs/ui/src/test-setup.ts
+++ b/libs/ui/src/test-setup.ts
@@ -1 +1,2 @@
+import 'hammerjs';
import 'jest-preset-angular';
diff --git a/libs/ui/tsconfig.spec.json b/libs/ui/tsconfig.spec.json
index 61c376d5..29121926 100644
--- a/libs/ui/tsconfig.spec.json
+++ b/libs/ui/tsconfig.spec.json
@@ -4,6 +4,6 @@
"outDir": "../../dist/out-tsc",
"types": ["jest", "node"]
},
- "files": ["src/test-setup.ts"],
+ "files": ["./src/test-setup.ts"],
"include": ["**/*.spec.ts", "**/*.d.ts"]
}
diff --git a/libs/vdb/README.md b/libs/vdb/README.md
index bc063f73..76cc2814 100644
--- a/libs/vdb/README.md
+++ b/libs/vdb/README.md
@@ -17,6 +17,7 @@ When manipulating data in OpenVDB, the three essential objects are
### Sources
+- [Repo](https://github.com/AcademySoftwareFoundation/openvdb)
- [Overview](https://www.openvdb.org/documentation/doxygen/overview.html)
- [Cookbook](https://www.openvdb.org/documentation/doxygen/codeExamples.html)
diff --git a/libs/vdb/src/lib/grid.spec.ts b/libs/vdb/src/lib/grid.spec.ts
new file mode 100644
index 00000000..262a0804
--- /dev/null
+++ b/libs/vdb/src/lib/grid.spec.ts
@@ -0,0 +1,26 @@
+import { Grid } from '@talus/vdb';
+
+describe('Grid', () => {
+ it('should get background', () => {
+ const grid = new Grid(-1);
+
+ expect(grid.background).toEqual(-1);
+ });
+
+ it('should iterate over each activated voxel', () => {
+ const grid = new Grid(-1);
+ const accessor = grid.getAccessor();
+
+ accessor.setValueOn([2, 1, 0], 42);
+ accessor.setValueOn([845, 64, 242], 42);
+ accessor.setValueOn([1000, 200000, 4000], 42);
+
+ let counter = 0;
+ for (const voxel of grid.beginVoxelOn()) {
+ counter++;
+ expect(voxel.value).toEqual(42);
+ }
+
+ expect(counter).toEqual(3);
+ });
+});
diff --git a/libs/vdb/src/lib/math/coord.spec.ts b/libs/vdb/src/lib/math/coord.spec.ts
new file mode 100644
index 00000000..a1b365d2
--- /dev/null
+++ b/libs/vdb/src/lib/math/coord.spec.ts
@@ -0,0 +1,28 @@
+import { add, areEqual, clone, Coord, createMinCoord } from './coord';
+
+describe('Coord', () => {
+ it('should add coordinates', () => {
+ const c1: Coord = [1, 2, 3];
+ const c2: Coord = [3, 2, 1];
+
+ expect(add(c1, c2)).toEqual([4, 4, 4]);
+ });
+
+ it('should create minimal coordinate', () => {
+ expect(createMinCoord()).toEqual([5e-324, 5e-324, 5e-324]);
+ });
+
+ it('should consider coordinates equal', () => {
+ const c1: Coord = [1, 2, 3];
+ const c2: Coord = [1, 2, 3];
+
+ expect(areEqual(c1, c2)).toBeTruthy();
+ });
+
+ it('should create clone', () => {
+ const c1: Coord = [1, 2, 3];
+
+ expect(clone(c1)).toEqual(c1);
+ expect(clone(c1)).not.toBe(c1);
+ });
+});
diff --git a/libs/vdb/src/lib/math/coord.ts b/libs/vdb/src/lib/math/coord.ts
index 0001351f..f0ec4069 100644
--- a/libs/vdb/src/lib/math/coord.ts
+++ b/libs/vdb/src/lib/math/coord.ts
@@ -24,3 +24,11 @@ export function createMaxCoord(): Coord {
export function createMinCoord(): Coord {
return [Number.MIN_VALUE, Number.MIN_VALUE, Number.MIN_VALUE];
}
+
+export function areEqual(c1: Coord, c2: Coord): boolean {
+ return c1[0] === c2[0] && c1[1] === c2[1] && c1[2] === c2[2];
+}
+
+export function clone(c: Coord): Coord {
+ return [c[0], c[1], c[2]];
+}
diff --git a/libs/vdb/src/lib/tools/grid-to-mesh.spec.ts b/libs/vdb/src/lib/tools/grid-to-mesh.spec.ts
deleted file mode 100644
index ab6a602f..00000000
--- a/libs/vdb/src/lib/tools/grid-to-mesh.spec.ts
+++ /dev/null
@@ -1,26 +0,0 @@
-import { Grid } from '../grid';
-import { gridToMesh } from './grid-to-mesh';
-
-describe('gridToMesh()', () => {
- it('should generate the mesh', () => {
- const grid = new Grid(0);
- const accessor = grid.getAccessor();
-
- accessor.setValue([0, 0, 0], 1);
- accessor.setValue([0, 0, 1], 1);
-
- const meshData = gridToMesh(grid);
-
- const voxels = 2;
-
- const corners = 8;
- const triangles = 12;
-
- const xyz = 3;
- const rgba = 4;
-
- expect(meshData.positions.length).toEqual(voxels * corners * xyz);
- expect(meshData.colors.length).toEqual(voxels * corners * rgba);
- expect(meshData.indices.length).toEqual(voxels * triangles * xyz);
- });
-});
diff --git a/libs/vdb/src/lib/tools/grid-to-mesh.ts b/libs/vdb/src/lib/tools/grid-to-mesh.ts
deleted file mode 100644
index fe5218ec..00000000
--- a/libs/vdb/src/lib/tools/grid-to-mesh.ts
+++ /dev/null
@@ -1,84 +0,0 @@
-/**
- * Babylon.js has a left-handed coordinate system with Y pointing up.
- * Furthermore, the front face of a facet is considered the face where the facet’s vertices
- * are positioned counterclockwise.
- *
- * Position of a facet is the location of the facet’s barycenter (a.k.a. centroid).
- *
- * 6-------7
- * /| /|
- * / | / |
- * Y 3--|----2 |
- * | Z | 5----|--4
- * | / | / | /
- * 0--- X 0-------1
- */
-
-import { Grid } from '../grid';
-
-export interface MeshData {
- colors: number[];
- indices: number[];
- // normals: number[];
- positions: number[];
-}
-
-/**
- * Returns a mesh if there are any active voxels saved in the grid.
- * Otherwise, returns `undefined` i.e. if there are no active voxels.
- */
-export function gridToMesh(grid: Grid): MeshData | undefined {
- const mesh: MeshData = {
- colors: [],
- indices: [],
- positions: [],
- // normals: [],
- };
-
- let vertexCount = 0;
- for (const voxel of grid.beginVoxelOn()) {
- const [x, y, z] = voxel.globalCoord;
-
- mesh.indices.push(...[5, 0, 3, 3, 6, 5].map(i => i + vertexCount)); // Left
- mesh.indices.push(...[1, 4, 7, 7, 2, 1].map(i => i + vertexCount)); // Right
-
- mesh.indices.push(...[5, 4, 1, 1, 0, 5].map(i => i + vertexCount)); // Bottom
- mesh.indices.push(...[7, 6, 3, 3, 2, 7].map(i => i + vertexCount)); // Top
-
- mesh.indices.push(...[0, 1, 2, 2, 3, 0].map(i => i + vertexCount)); // Front
- mesh.indices.push(...[4, 5, 6, 6, 7, 4].map(i => i + vertexCount)); // Back
-
- // mesh.normals.push(-1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0); // Left
- // mesh.normals.push(1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0); // Right
-
- // mesh.normals.push(0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0); // Bottom
- // mesh.normals.push(0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0); // Top
-
- // mesh.normals.push(0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1, 0, 0, -1); // Front
- // mesh.normals.push(0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1, 0, 0, 1); // Back
-
- mesh.positions.push(x, y, z); // 0
- mesh.positions.push(x + 1, y, z); // 1
- mesh.positions.push(x + 1, y + 1, z); // 2
- mesh.positions.push(x, y + 1, z); // 3
-
- mesh.positions.push(x + 1, y, z + 1); // 4
- mesh.positions.push(x, y, z + 1); // 5
- mesh.positions.push(x, y + 1, z + 1); // 6
- mesh.positions.push(x + 1, y + 1, z + 1); // 7
-
- vertexCount += 8;
-
- mesh.colors.push(0, 1, 0, 1);
- mesh.colors.push(0, 1, 0, 1);
- mesh.colors.push(0, 1, 0, 1);
- mesh.colors.push(0, 1, 0, 1);
-
- mesh.colors.push(0, 1, 0, 1);
- mesh.colors.push(0, 1, 0, 1);
- mesh.colors.push(0, 1, 0, 1);
- mesh.colors.push(0, 1, 0, 1);
- }
-
- return vertexCount !== 0 ? mesh : undefined;
-}
diff --git a/libs/vdb/src/lib/tools/index.ts b/libs/vdb/src/lib/tools/index.ts
index e2f1c696..479b8e5c 100644
--- a/libs/vdb/src/lib/tools/index.ts
+++ b/libs/vdb/src/lib/tools/index.ts
@@ -1 +1 @@
-export * from './grid-to-mesh';
+export * from './node-to-mesh';
diff --git a/libs/vdb/src/lib/tools/node-to-mesh.spec.ts b/libs/vdb/src/lib/tools/node-to-mesh.spec.ts
new file mode 100644
index 00000000..00337913
--- /dev/null
+++ b/libs/vdb/src/lib/tools/node-to-mesh.spec.ts
@@ -0,0 +1,37 @@
+import { Grid } from '../grid';
+import { nodeToMesh } from './node-to-mesh';
+
+describe('nodeToMesh()', () => {
+ it('should generate the mesh', () => {
+ const grid = new Grid(0);
+ const accessor = grid.getAccessor();
+
+ accessor.setValueOn([0, 0, 0], 1);
+ accessor.setValueOn([0, 0, 1], 1);
+
+ const meshData = nodeToMesh(grid.tree.root, () => [0, 0, 0, 1]);
+
+ const voxels = 2;
+
+ const triangles = 12;
+ const triangleCorners = triangles * 3;
+
+ const xyz = 3;
+ const rgba = 4;
+
+ expect(meshData).toBeDefined();
+ if (meshData) {
+ expect(meshData.positions.length).toEqual(voxels * triangleCorners * xyz);
+ expect(meshData.colors.length).toEqual(voxels * triangleCorners * rgba);
+ expect(meshData.normals.length).toEqual(meshData.positions.length);
+ }
+ });
+
+ it('should return undefined if there are no data', () => {
+ const grid = new Grid(0);
+
+ const meshData = nodeToMesh(grid.tree.root, () => [0, 0, 0, 1]);
+
+ expect(meshData).toBeUndefined();
+ });
+});
diff --git a/libs/vdb/src/lib/tools/node-to-mesh.ts b/libs/vdb/src/lib/tools/node-to-mesh.ts
new file mode 100644
index 00000000..d666417f
--- /dev/null
+++ b/libs/vdb/src/lib/tools/node-to-mesh.ts
@@ -0,0 +1,449 @@
+/**
+ * Babylon.js has a left-handed coordinate system with Y pointing up.
+ * Furthermore, the front face of a facet is considered the face where the facet’s vertices
+ * are positioned counterclockwise.
+ *
+ * Position of a facet is the location of the facet’s barycenter (a.k.a. centroid).
+ *
+ * 6-------7
+ * /| /|
+ * / | / |
+ * Y 3--|----2 |
+ * | Z | 5----|--4
+ * | / | / | /
+ * 0--- X 0-------1
+ */
+
+import { HashableNode } from '../tree/node';
+
+export interface MeshData {
+ colors: number[];
+ normals: number[];
+ positions: number[];
+}
+
+/**
+ * Returns a mesh if there are any active voxels saved in the grid.
+ * Otherwise, returns `undefined` i.e. if there are no active voxels.
+ *
+ * Doesn't use indices, since it is more efficient to send 32 positions
+ * instead of 24 positions and 32 indices for a cube.
+ * See: https://doc.babylonjs.com/how_to/optimizing_your_scene#using-unindexed-meshes
+ */
+export function nodeToMesh(
+ node: HashableNode,
+ valueToColor: (value: T) => [number, number, number, number],
+): MeshData | undefined {
+ const mesh: MeshData = {
+ colors: [],
+ positions: [],
+ normals: [],
+ };
+
+ for (const voxel of node.beginVoxelOn()) {
+ const [x, y, z] = voxel.globalCoord;
+ const [r, g, b, a] = valueToColor(voxel.value);
+
+ const v0 = [x, y, z];
+ const v1 = [x + 1, y, z];
+ const v2 = [x + 1, y + 1, z];
+ const v3 = [x, y + 1, z];
+ const v4 = [x + 1, y, z + 1];
+ const v5 = [x, y, z + 1];
+ const v6 = [x, y + 1, z + 1];
+ const v7 = [x + 1, y + 1, z + 1];
+
+ mesh.positions.push(
+ // Front
+ v4[0],
+ v4[1],
+ v4[2],
+ v5[0],
+ v5[1],
+ v5[2],
+ v6[0],
+ v6[1],
+ v6[2],
+ v4[0],
+ v4[1],
+ v4[2],
+ v6[0],
+ v6[1],
+ v6[2],
+ v7[0],
+ v7[1],
+ v7[2],
+
+ // Back
+ v0[0],
+ v0[1],
+ v0[2],
+ v1[0],
+ v1[1],
+ v1[2],
+ v2[0],
+ v2[1],
+ v2[2],
+ v0[0],
+ v0[1],
+ v0[2],
+ v2[0],
+ v2[1],
+ v2[2],
+ v3[0],
+ v3[1],
+ v3[2],
+
+ // Left
+ v5[0],
+ v5[1],
+ v5[2],
+ v0[0],
+ v0[1],
+ v0[2],
+ v3[0],
+ v3[1],
+ v3[2],
+ v5[0],
+ v5[1],
+ v5[2],
+ v3[0],
+ v3[1],
+ v3[2],
+ v6[0],
+ v6[1],
+ v6[2],
+
+ // Right
+ v1[0],
+ v1[1],
+ v1[2],
+ v4[0],
+ v4[1],
+ v4[2],
+ v7[0],
+ v7[1],
+ v7[2],
+ v1[0],
+ v1[1],
+ v1[2],
+ v7[0],
+ v7[1],
+ v7[2],
+ v2[0],
+ v2[1],
+ v2[2],
+
+ // Top
+ v3[0],
+ v3[1],
+ v3[2],
+ v2[0],
+ v2[1],
+ v2[2],
+ v7[0],
+ v7[1],
+ v7[2],
+ v3[0],
+ v3[1],
+ v3[2],
+ v7[0],
+ v7[1],
+ v7[2],
+ v6[0],
+ v6[1],
+ v6[2],
+
+ // Bottom
+ v5[0],
+ v5[1],
+ v5[2],
+ v4[0],
+ v4[1],
+ v4[2],
+ v1[0],
+ v1[1],
+ v1[2],
+ v5[0],
+ v5[1],
+ v5[2],
+ v1[0],
+ v1[1],
+ v1[2],
+ v0[0],
+ v0[1],
+ v0[2],
+ );
+
+ // Front
+ mesh.normals.push(
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+
+ // Back
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+
+ // Left
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+
+ // Right
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+
+ // Top
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+ 0,
+ 1,
+ 0,
+
+ // Bottom
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ 0,
+ -1,
+ 0,
+ );
+
+ mesh.colors.push(
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ r,
+ g,
+ b,
+ a,
+ );
+ }
+
+ return mesh.positions.length !== 0 ? mesh : undefined;
+}
diff --git a/libs/vdb/src/lib/tree/index.ts b/libs/vdb/src/lib/tree/index.ts
index 54c0aae2..6ed61bee 100644
--- a/libs/vdb/src/lib/tree/index.ts
+++ b/libs/vdb/src/lib/tree/index.ts
@@ -1 +1,2 @@
+export * from './leaf-node';
export * from './internal-node';
diff --git a/libs/vdb/src/lib/tree/internal-node.spec.ts b/libs/vdb/src/lib/tree/internal-node.spec.ts
index b8b51738..8307d50e 100644
--- a/libs/vdb/src/lib/tree/internal-node.spec.ts
+++ b/libs/vdb/src/lib/tree/internal-node.spec.ts
@@ -5,12 +5,12 @@ import { LeafNode } from './leaf-node';
describe('InternalNode', () => {
describe('InternalNode1', () => {
describe('static config values', () => {
- expect(InternalNode1.LOG2DIM).toEqual(2);
- expect(InternalNode1.TOTAL).toEqual(5);
- expect(InternalNode1.DIM).toEqual(32);
- expect(InternalNode1.NUM_VALUES).toEqual(64);
+ expect(InternalNode1.LOG2DIM).toEqual(3);
+ expect(InternalNode1.TOTAL).toEqual(3 + 3);
+ expect(InternalNode1.DIM).toEqual(64);
+ expect(InternalNode1.NUM_VALUES).toEqual(512);
expect(InternalNode1.LEVEL).toEqual(1);
- expect(InternalNode1.NUM_VOXELS).toEqual(32_768);
+ expect(InternalNode1.NUM_VOXELS).toEqual(262_144);
});
describe('setValueOn()', () => {
@@ -50,28 +50,28 @@ describe('InternalNode', () => {
describe('coordToOffset()', () => {
it.each([
[[0, 0, LeafNode.DIM], 1],
- [[0, LeafNode.DIM, LeafNode.DIM], 4 + 1],
- [[LeafNode.DIM, LeafNode.DIM, LeafNode.DIM], 16 + 4 + 1],
+ [[0, LeafNode.DIM, LeafNode.DIM], 8 + 1],
+ [[LeafNode.DIM, LeafNode.DIM, LeafNode.DIM], 64 + 8 + 1],
[[0, 0, LeafNode.DIM * 0], 0],
[[0, 0, LeafNode.DIM * 1], 1],
[[0, 0, LeafNode.DIM * 2], 2],
[[0, 0, LeafNode.DIM * 3], 3],
- [[0, LeafNode.DIM * 0, 0], 0 * 4],
- [[0, LeafNode.DIM * 1, 0], 1 * 4],
- [[0, LeafNode.DIM * 2, 0], 2 * 4],
- [[0, LeafNode.DIM * 3, 0], 3 * 4],
+ [[0, LeafNode.DIM * 0, 0], 0 * 8],
+ [[0, LeafNode.DIM * 1, 0], 1 * 8],
+ [[0, LeafNode.DIM * 2, 0], 2 * 8],
+ [[0, LeafNode.DIM * 3, 0], 3 * 8],
- [[LeafNode.DIM * 0, 0, 0], 0 * 16],
- [[LeafNode.DIM * 1, 0, 0], 1 * 16],
- [[LeafNode.DIM * 2, 0, 0], 2 * 16],
- [[LeafNode.DIM * 3, 0, 0], 3 * 16],
+ [[LeafNode.DIM * 0, 0, 0], 0 * 64],
+ [[LeafNode.DIM * 1, 0, 0], 1 * 64],
+ [[LeafNode.DIM * 2, 0, 0], 2 * 64],
+ [[LeafNode.DIM * 3, 0, 0], 3 * 64],
- // 24 / 8 = 3 -> 3 x 16 = 48 â•®
- // 9 / 8 = 1 -> 1 x 4 = 4 ├─> 48 + 4 + 2 = 54
- // 17 / 8 = 2 -> 2 x 1 = 2 ╯
- [[24, 9, 17], 54],
+ // 24 / 8 = 3 -> 3 x 64 = 192 â•®
+ // 9 / 8 = 1 -> 1 x 8 = 8 ├─> 192 + 8 + 2 = 202
+ // 17 / 8 = 2 -> 2 x 1 = 2 ╯
+ [[24, 9, 17], 202],
])('should return for coordinate %j the offset (%j)', (xyz: Coord, offset: number) => {
const child = new InternalNode1([0, 0, 0]);
@@ -82,11 +82,12 @@ describe('InternalNode', () => {
describe('isValueOn()', () => {
it('should set each voxel', () => {
const node1 = new InternalNode1([0, 0, 0]);
+ const maxDim = InternalNode1.DIM / 4; // Shorten test running time
let onCounter = 0;
- for (let x = 0; x < InternalNode1.DIM; x++) {
- for (let y = 0; y < InternalNode1.DIM; y++) {
- for (let z = 0; z < InternalNode1.DIM; z++) {
+ for (let x = 0; x < maxDim; x++) {
+ for (let y = 0; y < maxDim; y++) {
+ for (let z = 0; z < maxDim; z++) {
node1.setValueOn([x, y, z], onCounter);
expect(node1.getValue([x, y, z])).toEqual(onCounter);
@@ -95,18 +96,19 @@ describe('InternalNode', () => {
}
}
- expect(onCounter).toEqual(Math.pow(InternalNode1.DIM, 3));
+ expect(onCounter).toEqual(Math.pow(maxDim, 3));
});
});
describe('onVoxelCount()', () => {
it('should count all activated voxels', () => {
const node1 = new InternalNode1([0, 0, 0]);
+ const maxDim = InternalNode1.DIM / 4; // Shorten test running time
let onCounter = 0;
- for (let x = 0; x < InternalNode1.DIM; x++) {
- for (let y = 0; y < InternalNode1.DIM; y++) {
- for (let z = 0; z < InternalNode1.DIM; z++) {
+ for (let x = 0; x < maxDim; x++) {
+ for (let y = 0; y < maxDim; y++) {
+ for (let z = 0; z < maxDim; z++) {
node1.setValueOn([x, y, z], 42);
onCounter++;
@@ -115,7 +117,7 @@ describe('InternalNode', () => {
}
}
- expect(onCounter).toEqual(Math.pow(InternalNode1.DIM, 3));
+ expect(onCounter).toEqual(Math.pow(maxDim, 3));
});
});
@@ -143,11 +145,11 @@ describe('InternalNode', () => {
describe('InternalNode2', () => {
describe('static config values', () => {
expect(InternalNode2.LOG2DIM).toEqual(2);
- expect(InternalNode2.TOTAL).toEqual(7);
- expect(InternalNode2.DIM).toEqual(128);
+ expect(InternalNode2.TOTAL).toEqual(2 + 3 + 3);
+ expect(InternalNode2.DIM).toEqual(256);
expect(InternalNode2.NUM_VALUES).toEqual(64);
expect(InternalNode2.LEVEL).toEqual(2);
- expect(InternalNode2.NUM_VOXELS).toEqual(2_097_152);
+ expect(InternalNode2.NUM_VOXELS).toEqual(16_777_216);
});
describe('setValueOn()', () => {
@@ -176,14 +178,14 @@ describe('InternalNode', () => {
describe('coordToOffset()', () => {
it.each([
[[0, 0, 0], 0],
- [[0, 0, 128], 0],
- [[0, 0, 32], 1],
- [[0, 0, 64], 2],
- [[0, 0, 96], 3],
-
- [[0, 0, 32], 1],
- [[0, 32, 0], 4],
- [[32, 0, 0], 16],
+ [[0, 0, 256], 0],
+ [[0, 0, 64], 1],
+ [[0, 0, 128], 2],
+ [[0, 0, 192], 3],
+
+ [[0, 0, 64], 1],
+ [[0, 64, 0], 4],
+ [[64, 0, 0], 16],
])('should return for coordinate %j the offset (%j)', (xyz: Coord, offset: number) => {
const child = new InternalNode2([0, 0, 0]);
@@ -194,18 +196,19 @@ describe('InternalNode', () => {
describe('onVoxelCount()', () => {
it('should count all activated voxels', () => {
const node2 = new InternalNode2([0, 0, 0]);
+ const maxDim = InternalNode2.DIM / 4; // Shorten test running time
let onCounter = 0;
- for (let x = 0; x < InternalNode2.DIM; x++) {
- for (let y = 0; y < InternalNode2.DIM; y++) {
- for (let z = 0; z < InternalNode2.DIM; z++) {
+ for (let x = 0; x < maxDim; x++) {
+ for (let y = 0; y < maxDim; y++) {
+ for (let z = 0; z < maxDim; z++) {
node2.setValueOn([x, y, z], 42);
onCounter++;
}
}
}
- expect(onCounter).toEqual(Math.pow(InternalNode2.DIM, 3));
+ expect(onCounter).toEqual(Math.pow(maxDim, 3));
});
});
diff --git a/libs/vdb/src/lib/tree/internal-node.ts b/libs/vdb/src/lib/tree/internal-node.ts
index 306bce01..072d7e9c 100644
--- a/libs/vdb/src/lib/tree/internal-node.ts
+++ b/libs/vdb/src/lib/tree/internal-node.ts
@@ -8,9 +8,9 @@ import { ValueAccessor3 } from './value-accessor';
import { Voxel } from './voxel';
abstract class InternalNode implements HashableNode {
+ origin: Coord;
protected childMask: NodeMask;
protected valueMask: NodeMask;
- protected origin: Coord;
protected nodes: NodeUnion>[];
@@ -78,6 +78,23 @@ abstract class InternalNode implements HashableNode {
return node.getValue();
}
+ probeInternalNode1AndCache(
+ xyz: Coord,
+ accessor: ValueAccessor3,
+ ): InternalNode1 | undefined {
+ const i: Index = this.coordToOffset(xyz);
+ const node = this.nodes[i];
+
+ if (this.childMask.isOff(i)) {
+ return undefined;
+ }
+
+ const child = node.getChild();
+ accessor.insert(xyz, child);
+
+ return child instanceof InternalNode1 ? child : child.probeInternalNode1AndCache(xyz, accessor);
+ }
+
setValueOn(xyz: Coord, value: T): void {
const i: Index = this.coordToOffset(xyz);
const node = this.nodes[i];
@@ -146,6 +163,27 @@ abstract class InternalNode implements HashableNode {
}
}
+ setActiveStateAndCache(xyz: Coord, on: boolean, accessor: ValueAccessor3): void {
+ const i: Index = this.coordToOffset(xyz);
+ const node = this.nodes[i];
+ let hasChild = this.childMask.isOn(i);
+
+ if (!hasChild) {
+ if (on !== this.valueMask.isOn(i)) {
+ // If the voxel belongs to a tile with the wrong active state,
+ // then a child subtree must be constructed.
+ // 'on' is the voxel's new state, therefore '!on' is the tile's current state
+ hasChild = true;
+ this.setChildNode(i, this.createChildNode(xyz, node.getValue(), !on));
+ }
+ }
+
+ if (hasChild) {
+ accessor.insert(xyz, node.getChild());
+ node.getChild().setActiveStateAndCache(xyz, on, accessor);
+ }
+ }
+
isValueOn(xyz: Coord): boolean {
const i: Index = this.coordToOffset(xyz);
if (this.childMask.isOff(i)) {
@@ -242,7 +280,7 @@ abstract class InternalNode implements HashableNode {
export class InternalNode1 extends InternalNode {
// tslint:disable:no-bitwise
- static readonly LOG2DIM = 2; // log2 of tile count in one dimension
+ static readonly LOG2DIM = 3; // log2 of tile count in one dimension
static readonly TOTAL = InternalNode1.LOG2DIM + LeafNode.TOTAL; // log2 of voxel count in one dimension
static readonly DIM = 1 << InternalNode1.TOTAL; // total voxel count in one dimension
static readonly DIM_MAX_INDEX_INVERTED: Index = ~(InternalNode1.DIM - 1); // Performance: max index
diff --git a/libs/vdb/src/lib/tree/leaf-node.ts b/libs/vdb/src/lib/tree/leaf-node.ts
index 4cada089..b7d9b10d 100644
--- a/libs/vdb/src/lib/tree/leaf-node.ts
+++ b/libs/vdb/src/lib/tree/leaf-node.ts
@@ -1,5 +1,6 @@
import { Coord } from '../math/coord';
import { NodeMask } from '../util/node-mask';
+import { InternalNode1 } from './internal-node';
import { LeafBuffer } from './leaf-buffer';
import { HashableNode } from './node';
import { ValueAccessor3 } from './value-accessor';
@@ -21,12 +22,13 @@ export class LeafNode implements HashableNode {
static readonly LEVEL: Index = 0; // level 0 = leaf
// tslint:enable:no-bitwise
+ // Global grid index coordinates (x,y,z) of the local origin of this node
+ readonly origin: Coord;
+
// Buffer containing the actual data values
private buffer: LeafBuffer;
// Bitmask that determines which voxels are active
private valueMask: NodeMask;
- // Global grid index coordinates (x,y,z) of the local origin of this node
- private readonly origin: Coord;
/**
* Return the linear table offset of the given global or local coordinates.
@@ -96,6 +98,13 @@ export class LeafNode implements HashableNode {
this.valueMask.setOff(offset);
}
+ /**
+ * Set the active state of the voxel at the given coordinates but don't change its value.
+ */
+ setActiveState(xyz: Coord, on: boolean): void {
+ this.valueMask.set(LeafNode.coordToOffset(xyz), on);
+ }
+
/**
* Return the value of the voxel at the given coordinates.
*/
@@ -119,6 +128,10 @@ export class LeafNode implements HashableNode {
return this.getValue(xyz);
}
+ probeInternalNode1AndCache(xyz: Coord, _: ValueAccessor3): InternalNode1 | undefined {
+ throw new Error(`Shouldn't be called on LeafNode`);
+ }
+
/**
* @brief Change the value of the voxel at the given coordinates and mark it as active.
* @note Used internally by ValueAccessor.
@@ -143,6 +156,14 @@ export class LeafNode implements HashableNode {
return this.isValueOn(xyz);
}
+ /**
+ * @brief Set the active state of the voxel at the given coordinates without changing its value.
+ * @note Used internally by ValueAccessor.
+ */
+ setActiveStateAndCache(xyz: Coord, on: boolean, _: ValueAccessor3): void {
+ return this.setActiveState(xyz, on);
+ }
+
/**
* Return the global coordinates for a linear table offset.
*/
diff --git a/libs/vdb/src/lib/tree/node.ts b/libs/vdb/src/lib/tree/node.ts
index e4c34174..01d4c8cc 100644
--- a/libs/vdb/src/lib/tree/node.ts
+++ b/libs/vdb/src/lib/tree/node.ts
@@ -1,3 +1,4 @@
+import { InternalNode1 } from '@talus/vdb';
import { Coord } from '../math/coord';
import { ValueAccessor3 } from './value-accessor';
import { Voxel } from './voxel';
@@ -33,11 +34,18 @@ export interface HashableNode extends Node {
*/
getValueAndCache(xyz: Coord, accessor: ValueAccessor3): T;
+ /**
+ * Same as probeNode() except, if necessary, update the accessor with pointers
+ * to the nodes along the path from the root node to the node containing (x, y, z).
+ */
+ probeInternalNode1AndCache(xyz: Coord, accessor: ValueAccessor3): InternalNode1 | undefined;
+
/**
* Change the value of the voxel at the given coordinates and mark it as active.
* If necessary, update the accessor with pointers to the nodes along the path
* from the root node to the node containing the voxel.
* @note Used internally by ValueAccessor.
+ * @return The affected `LeafNode` in which a value was set.
*/
setValueAndCache(xyz: Coord, value: T, accessor: ValueAccessor3): void;
@@ -56,6 +64,14 @@ export interface HashableNode extends Node {
* @note Used internally by ValueAccessor.
*/
isValueOnAndCache(xyz: Coord, accessor: ValueAccessor3): boolean;
+
+ /**
+ * Set the active state of the voxel at the given coordinates without changing its value.
+ * If necessary, update the accessor with pointers to the nodes along the path
+ * from the root node to the node containing the voxel.
+ * @note Used internally by ValueAccessor.
+ */
+ setActiveStateAndCache(xyz: Coord, on: boolean, accessor: ValueAccessor3): void;
}
export interface IterableNode {
diff --git a/libs/vdb/src/lib/tree/root-node.spec.ts b/libs/vdb/src/lib/tree/root-node.spec.ts
index 6ee42d90..47b1d179 100644
--- a/libs/vdb/src/lib/tree/root-node.spec.ts
+++ b/libs/vdb/src/lib/tree/root-node.spec.ts
@@ -2,95 +2,93 @@ import { InternalNode2 } from './internal-node';
import { RootNode } from './root-node';
describe('RootNode', () => {
- describe('setValueOn()', () => {
- it('should set given value and activate it', () => {
- const root = new RootNode(-1);
+ it('should set given value and activate it', () => {
+ const root = new RootNode(-1);
- root.setValueOn([0, 0, 0], 24);
- root.setValueOn([102, 15, 127], 42);
+ root.setValueOn([0, 0, 0], 24);
+ root.setValueOn([102, 15, 127], 42);
- expect(root.getValue([0, 0, 0])).toEqual(24);
- expect(root.getValue([102, 15, 127])).toEqual(42);
+ expect(root.getValue([0, 0, 0])).toEqual(24);
+ expect(root.getValue([102, 15, 127])).toEqual(42);
- expect(root.isValueOn([0, 0, 0])).toEqual(true);
- expect(root.isValueOn([102, 15, 127])).toEqual(true);
+ expect(root.isValueOn([0, 0, 0])).toEqual(true);
+ expect(root.isValueOn([102, 15, 127])).toEqual(true);
- expect(root.getValue([1, 1, 1])).toEqual(-1);
- });
+ expect(root.getValue([1, 1, 1])).toEqual(-1);
+ });
+
+ it('should return background', () => {
+ const root = new RootNode(-1);
+
+ expect(root.getValue([111, 222, 333])).toEqual(-1);
+ });
- it('should set value when given float coordinates', () => {
- const root = new RootNode(-1);
+ it('should set value when given float coordinates', () => {
+ const root = new RootNode(-1);
- root.setValueOn([0, 0, 0.1], 1);
- root.setValueOn([0, 1.5, 0], 5);
- root.setValueOn([2.9, 0, 0], 9);
+ root.setValueOn([0, 0, 0.1], 1);
+ root.setValueOn([0, 1.5, 0], 5);
+ root.setValueOn([2.9, 0, 0], 9);
- expect(root.getValue([0, 0, 0])).toEqual(1);
- expect(root.getValue([0, 0, 1])).toEqual(-1);
- expect(root.getValue([0, 1, 0])).toEqual(5);
- expect(root.getValue([0, 2, 0])).toEqual(-1);
- expect(root.getValue([2, 0, 0])).toEqual(9);
- expect(root.getValue([3, 0, 0])).toEqual(-1);
+ expect(root.getValue([0, 0, 0])).toEqual(1);
+ expect(root.getValue([0, 0, 1])).toEqual(-1);
+ expect(root.getValue([0, 1, 0])).toEqual(5);
+ expect(root.getValue([0, 2, 0])).toEqual(-1);
+ expect(root.getValue([2, 0, 0])).toEqual(9);
+ expect(root.getValue([3, 0, 0])).toEqual(-1);
- root.setValueOn([0, 0, -1.2], -2);
- root.setValueOn([0, -2.5, 0], -5);
- root.setValueOn([-3.9, 0, 0], -9);
+ root.setValueOn([0, 0, -1.2], -2);
+ root.setValueOn([0, -2.5, 0], -5);
+ root.setValueOn([-3.9, 0, 0], -9);
- expect(root.getValue([0, 0, -1])).toEqual(-2);
- expect(root.getValue([0, -2, 0])).toEqual(-5);
- expect(root.getValue([-3, 0, 0])).toEqual(-9);
- });
+ expect(root.getValue([0, 0, -1])).toEqual(-2);
+ expect(root.getValue([0, -2, 0])).toEqual(-5);
+ expect(root.getValue([-3, 0, 0])).toEqual(-9);
});
- describe('onVoxelCount()', () => {
- it('should count all activated voxels', () => {
- const root = new RootNode(-1);
+ it('should count all activated voxels', () => {
+ const root = new RootNode(-1);
- root.setValueOn([0, 0, 0], 24);
- root.setValueOn([102, 15, 127], 42);
+ root.setValueOn([0, 0, 0], 24);
+ root.setValueOn([102, 15, 127], 42);
- expect(root.onVoxelCount()).toEqual(2);
- });
+ expect(root.onVoxelCount()).toEqual(2);
});
- describe('getTableSize()', () => {
- it('should create new entries when inserting values', () => {
- const root = new RootNode(-1);
-
- root.setValueOn([0, 0, 0], 24);
- root.setValueOn([0, 0, 1], 24);
- root.setValueOn([102, 15, 127], 42);
- expect(root.getTableSize()).toEqual(1);
-
- root.setValueOn([0, 0, InternalNode2.DIM], 42);
- root.setValueOn([0, 1, InternalNode2.DIM], 42);
- root.setValueOn([1, 0, InternalNode2.DIM], 42);
- expect(root.getTableSize()).toEqual(2);
-
- root.setValueOn([InternalNode2.DIM, 0, 0], 42);
- root.setValueOn([InternalNode2.DIM, 0, 1], 42);
- root.setValueOn([InternalNode2.DIM, 1, 0], 42);
- expect(root.getTableSize()).toEqual(3);
- });
+ it('should create new entries when inserting values', () => {
+ const root = new RootNode(-1);
+
+ root.setValueOn([0, 0, 0], 24);
+ root.setValueOn([0, 0, 1], 24);
+ root.setValueOn([102, 15, 127], 42);
+ expect(root.getTableSize()).toEqual(1);
+
+ root.setValueOn([0, 0, InternalNode2.DIM], 42);
+ root.setValueOn([0, 1, InternalNode2.DIM], 42);
+ root.setValueOn([1, 0, InternalNode2.DIM], 42);
+ expect(root.getTableSize()).toEqual(2);
+
+ root.setValueOn([InternalNode2.DIM, 0, 0], 42);
+ root.setValueOn([InternalNode2.DIM, 0, 1], 42);
+ root.setValueOn([InternalNode2.DIM, 1, 0], 42);
+ expect(root.getTableSize()).toEqual(3);
});
- describe('beginVoxelOn()', () => {
- it('should iterate over all activated voxels', () => {
- const root = new RootNode(-1);
- const expectedValues = [0, 1, 2, 3];
+ it('should iterate over all activated voxels', () => {
+ const root = new RootNode(-1);
+ const expectedValues = [0, 1, 2, 3];
- root.setValueOn([0, 0, 0], expectedValues[0]);
- root.setValueOn([0, 0, InternalNode2.DIM], expectedValues[1]);
- root.setValueOn([0, InternalNode2.DIM, 0], expectedValues[2]);
- root.setValueOn([InternalNode2.DIM, 0, 0], expectedValues[3]);
+ root.setValueOn([0, 0, 0], expectedValues[0]);
+ root.setValueOn([0, 0, InternalNode2.DIM], expectedValues[1]);
+ root.setValueOn([0, InternalNode2.DIM, 0], expectedValues[2]);
+ root.setValueOn([InternalNode2.DIM, 0, 0], expectedValues[3]);
- let counter = 0;
- for (const voxel of root.beginVoxelOn()) {
- expect(voxel.value).toEqual(expectedValues[counter]);
- counter++;
- }
+ let counter = 0;
+ for (const voxel of root.beginVoxelOn()) {
+ expect(voxel.value).toEqual(expectedValues[counter]);
+ counter++;
+ }
- expect(counter).toEqual(expectedValues.length);
- });
+ expect(counter).toEqual(expectedValues.length);
});
});
diff --git a/libs/vdb/src/lib/tree/root-node.ts b/libs/vdb/src/lib/tree/root-node.ts
index 20d3dc9e..8366e667 100644
--- a/libs/vdb/src/lib/tree/root-node.ts
+++ b/libs/vdb/src/lib/tree/root-node.ts
@@ -1,5 +1,5 @@
import { Coord } from '../math/coord';
-import { InternalNode2 } from './internal-node';
+import { InternalNode1, InternalNode2 } from './internal-node';
import { HashableNode } from './node';
import { ValueAccessor3 } from './value-accessor';
import { Voxel } from './voxel';
@@ -57,9 +57,25 @@ export class RootNode implements HashableNode {
return struct.getTile().value;
}
+ probeInternalNode1AndCache(
+ xyz: Coord,
+ accessor: ValueAccessor3,
+ ): InternalNode1 | undefined {
+ const struct = this.findCoord(xyz);
+
+ if (!struct || struct.isTile()) {
+ return undefined;
+ }
+
+ const child = struct.getChild();
+ accessor.insert(xyz, child);
+
+ return child.probeInternalNode1AndCache(xyz, accessor);
+ }
+
setValueOn(xyz: Coord, value: T): void {
+ let child: HashableNode | undefined;
const struct = this.findCoord(xyz);
- let child: HashableNode;
if (!struct) {
child = new InternalNode2(xyz, this._background);
@@ -77,7 +93,7 @@ export class RootNode implements HashableNode {
}
setValueAndCache(xyz: Coord, value: T, accessor: ValueAccessor3): void {
- let child: HashableNode;
+ let child: HashableNode | undefined;
const struct = this.findCoord(xyz);
if (!struct) {
@@ -92,12 +108,12 @@ export class RootNode implements HashableNode {
if (child) {
accessor.insert(xyz, child);
- child.setValueOn(xyz, value);
+ child.setValueAndCache(xyz, value, accessor);
}
}
setValueOffAndCache(xyz: Coord, value: T, accessor: ValueAccessor3): void {
- let child: HashableNode;
+ let child: HashableNode | undefined;
const struct = this.findCoord(xyz);
if (!struct) {
@@ -118,6 +134,30 @@ export class RootNode implements HashableNode {
}
}
+ setActiveStateAndCache(xyz: Coord, on: boolean, accessor: ValueAccessor3): void {
+ let child: HashableNode | undefined;
+ const struct = this.findCoord(xyz);
+
+ if (!struct) {
+ if (on) {
+ child = new InternalNode2(xyz, this._background);
+ this.table.set(RootNode.coordToKey(xyz), new NodeStruct(child));
+ } /*else {
+ // Nothing to do; (x, y, z) is background and therefore already inactive.
+ }*/
+ } else if (struct.isChild()) {
+ child = struct.getChild();
+ } else if (on !== struct.getTile().active) {
+ child = new InternalNode2(xyz, struct.getTile().value, !on);
+ struct.setChild(child);
+ }
+
+ if (child) {
+ accessor.insert(xyz, child);
+ child.setActiveStateAndCache(xyz, on, accessor);
+ }
+ }
+
isValueOn(xyz: Coord): boolean {
const struct = this.findCoord(xyz);
@@ -186,6 +226,10 @@ class NodeStruct {
constructor(private child?: HashableNode) {}
getChild(): HashableNode {
+ if (!this.child) {
+ throw new Error('Access undefined child.');
+ }
+
return this.child;
}
diff --git a/libs/vdb/src/lib/tree/tree.spec.ts b/libs/vdb/src/lib/tree/tree.spec.ts
new file mode 100644
index 00000000..6e86aa4f
--- /dev/null
+++ b/libs/vdb/src/lib/tree/tree.spec.ts
@@ -0,0 +1,51 @@
+import { Tree } from './tree';
+
+describe('Tree', () => {
+ it('should get background', () => {
+ const tree = new Tree(-1);
+
+ expect(tree.background).toEqual(-1);
+ });
+
+ it('should get/set value', () => {
+ const tree = new Tree(-1);
+
+ tree.setValueOn([0, 1, 2], 42);
+
+ expect(tree.getValue([0, 1, 2])).toEqual(42);
+ });
+
+ it('should activated value', () => {
+ const tree = new Tree(-1);
+
+ tree.setValueOn([0, 1, 2], 42);
+
+ expect(tree.isValueOn([0, 1, 2])).toBeTruthy();
+ });
+
+ it('should count voxel', () => {
+ const tree = new Tree(-1);
+
+ tree.setValueOn([0, 1, 2], 42);
+ tree.setValueOn([845, 242, 64], 42);
+ tree.setValueOn([1000, 4000, 200000], 42);
+
+ expect(tree.onVoxelCount()).toEqual(3);
+ });
+
+ it('should iterate over each activated voxel', () => {
+ const tree = new Tree(-1);
+
+ tree.setValueOn([0, 1, 2], 42);
+ tree.setValueOn([845, 242, 64], 42);
+ tree.setValueOn([1000, 4000, 200000], 42);
+
+ let counter = 0;
+ for (const voxel of tree.beginVoxelOn()) {
+ counter++;
+ expect(voxel.value).toEqual(42);
+ }
+
+ expect(counter).toEqual(3);
+ });
+});
diff --git a/libs/vdb/src/lib/tree/value-accessor.spec.ts b/libs/vdb/src/lib/tree/value-accessor.spec.ts
index 425daade..8398e31b 100644
--- a/libs/vdb/src/lib/tree/value-accessor.spec.ts
+++ b/libs/vdb/src/lib/tree/value-accessor.spec.ts
@@ -1,8 +1,16 @@
-import { InternalNode2 } from './internal-node';
+import { LeafNode } from '@talus/vdb';
+import { InternalNode1, InternalNode2 } from './internal-node';
import { Tree } from './tree';
import { ValueAccessor3 } from './value-accessor';
describe('ValueAccessor', () => {
+ it('should return background', () => {
+ const tree = new Tree(-1);
+ const accessor = new ValueAccessor3(tree);
+
+ expect(accessor.getValue([111, 222, 333])).toEqual(-1);
+ });
+
describe('getValue()', () => {
it('should cache coordinate', () => {
const tree = new Tree(0);
@@ -22,12 +30,12 @@ describe('ValueAccessor', () => {
});
});
- describe('setValue()', () => {
+ describe('setValueOn()', () => {
it('should cache coordinate', () => {
const tree = new Tree(0);
const accessor = new ValueAccessor3(tree);
- accessor.setValue([0, 0, 0], 1496);
+ accessor.setValueOn([0, 0, 0], 1496);
const value = accessor.getValue([0, 0, 0]);
expect(value).toEqual(1496);
@@ -64,6 +72,27 @@ describe('ValueAccessor', () => {
});
});
+ describe('setActiveState()', () => {
+ it('should set state', () => {
+ const tree = new Tree(0);
+ const accessor = new ValueAccessor3(tree);
+
+ accessor.setValueOn([0, 0, 0], 1496);
+ expect(accessor.getValue([0, 0, 0])).toEqual(1496);
+ expect(accessor.isValueOn([0, 0, 0])).toEqual(true);
+
+ accessor.setActiveState([0, 0, 0], false);
+ expect(accessor.getValue([0, 0, 0])).toEqual(1496);
+ expect(accessor.isValueOn([0, 0, 0])).toBeFalsy();
+
+ accessor.setActiveState([0, 0, 0], true);
+ expect(accessor.getValue([0, 0, 0])).toEqual(1496);
+ expect(accessor.isValueOn([0, 0, 0])).toBeTruthy();
+
+ expect(accessor.isCached([0, 0, 0])).toBeTruthy();
+ });
+ });
+
describe('isValueOn()', () => {
it('should set value and (de)activate voxel', () => {
const tree = new Tree(0);
@@ -82,4 +111,42 @@ describe('ValueAccessor', () => {
expect(accessor.isValueOn([0, 0, 1])).toBeFalsy();
});
});
+
+ describe('probeInternalNode1()', () => {
+ const tree = new Tree(-1);
+
+ it('should return undefined if no internal node 1', () => {
+ const accessor = new ValueAccessor3(tree);
+
+ expect(accessor.probeInternalNode1([111, 222, 333])).toBeUndefined();
+ });
+
+ it('should hit no cache and return internal node 1', () => {
+ const accessor = new ValueAccessor3(tree);
+
+ accessor.setValueOn([0, 0, 0], 42);
+ // Produce a cache miss (go over root)
+ accessor.setValueOn([InternalNode2.DIM, 0, 0], 42);
+
+ expect(accessor.probeInternalNode1([32, 0, 0])).toBeInstanceOf(InternalNode1);
+ });
+
+ it('should hit cache L2 and return internal node 1', () => {
+ const accessor = new ValueAccessor3(tree);
+
+ accessor.setValueOn([0, 0, 0], 42);
+ // Produce a cache miss (go over InternalNode2)
+ accessor.setValueOn([InternalNode1.DIM, 0, 0], 42);
+
+ expect(accessor.probeInternalNode1([32, 0, 0])).toBeInstanceOf(InternalNode1);
+ });
+
+ it('should hit cache L1 and return internal node 1', () => {
+ const accessor = new ValueAccessor3(tree);
+
+ accessor.setValueOn([0, 0, 0], 42);
+
+ expect(accessor.probeInternalNode1([LeafNode.DIM, 0, 0])).toBeInstanceOf(InternalNode1);
+ });
+ });
});
diff --git a/libs/vdb/src/lib/tree/value-accessor.ts b/libs/vdb/src/lib/tree/value-accessor.ts
index 9ba01796..484a1ba6 100644
--- a/libs/vdb/src/lib/tree/value-accessor.ts
+++ b/libs/vdb/src/lib/tree/value-accessor.ts
@@ -1,4 +1,4 @@
-import { Coord, createMaxCoord } from '../math/coord';
+import { clone, Coord, createMaxCoord } from '../math/coord';
import { InternalNode1, InternalNode2 } from './internal-node';
import { LeafNode } from './leaf-node';
import { HashableNode } from './node';
@@ -28,7 +28,9 @@ import { Tree } from './tree';
* The configuration is hard-coded and has a depth of four.
*/
export class ValueAccessor3 {
- constructor(private tree: Tree) {}
+ get internalNode1Origin(): Coord {
+ return clone(this.internalKey1);
+ }
private leafKey: Coord = createMaxCoord();
private leafNode: LeafNode;
@@ -39,6 +41,8 @@ export class ValueAccessor3 {
private internalKey2: Coord = createMaxCoord();
private internalNode2: InternalNode2;
+ constructor(private tree: Tree) {}
+
/**
* Return true if any of the nodes along the path to the given voxel have been cached.
*/
@@ -46,6 +50,20 @@ export class ValueAccessor3 {
return this.isHashed2(xyz) || this.isHashed1(xyz) || this.isHashed0(xyz);
}
+ /**
+ * @returns Returns the node that contains voxel (x, y, z)
+ * and if it doesn't exist, return undefined.
+ */
+ probeInternalNode1(xyz: Coord): InternalNode1 | undefined {
+ if (this.isHashed1(xyz)) {
+ return this.internalNode1;
+ } else if (this.isHashed2(xyz)) {
+ return this.internalNode2.probeInternalNode1AndCache(xyz, this);
+ } else {
+ return this.tree.root.probeInternalNode1AndCache(xyz, this);
+ }
+ }
+
/**
* Return the value of the voxel at the given coordinates.
*/
@@ -64,7 +82,7 @@ export class ValueAccessor3 {
/**
* Set the value of the voxel at the given coordinates and mark the voxel as active.
*/
- setValue(xyz: Coord, value: T): void {
+ setValueOn(xyz: Coord, value: T): void {
if (this.isHashed0(xyz)) {
this.leafNode.setValueAndCache(xyz, value, this);
} else if (this.isHashed1(xyz)) {
@@ -75,9 +93,6 @@ export class ValueAccessor3 {
this.tree.root.setValueAndCache(xyz, value, this);
}
}
- setValueOn(xyz: Coord, value: T): void {
- this.setValue(xyz, value);
- }
/**
* Set the value of the voxel at the given coordinates and mark the voxel as inactive.
@@ -108,6 +123,20 @@ export class ValueAccessor3 {
return this.tree.root.isValueOnAndCache(xyz, this);
}
+ /**
+ * Set the active state of the voxel at the given coordinates without changing its value.
+ */
+ setActiveState(xyz: Coord, on: boolean): void {
+ if (this.isHashed0(xyz)) {
+ this.leafNode.setActiveStateAndCache(xyz, on, this);
+ } else if (this.isHashed1(xyz)) {
+ this.internalNode1.setActiveStateAndCache(xyz, on, this);
+ } else if (this.isHashed2(xyz)) {
+ this.internalNode2.setActiveStateAndCache(xyz, on, this);
+ }
+ this.tree.root.setActiveStateAndCache(xyz, on, this);
+ }
+
// tslint:disable:no-bitwise
insert(xyz: Coord, node: HashableNode): void {
if (node instanceof LeafNode) {
diff --git a/libs/vdb/src/lib/util/node-mask.ts b/libs/vdb/src/lib/util/node-mask.ts
index a654a154..5c45e9a8 100644
--- a/libs/vdb/src/lib/util/node-mask.ts
+++ b/libs/vdb/src/lib/util/node-mask.ts
@@ -51,4 +51,8 @@ export class NodeMask {
isOff(i: Index): boolean {
return this.mask.test(i) === false;
}
+
+ set(i: Index, on: boolean): void {
+ on ? this.setOn(i) : this.setOff(i);
+ }
}
diff --git a/libs/vdb/tslint.json b/libs/vdb/tslint.json
index 04809f83..8e2f21b3 100644
--- a/libs/vdb/tslint.json
+++ b/libs/vdb/tslint.json
@@ -1 +1,4 @@
-{ "extends": "../../tslint.json", "rules": [] }
+{
+ "extends": "../../tslint.json",
+ "rules": {}
+}
diff --git a/package.json b/package.json
index dd0b33a6..512b2fa6 100644
--- a/package.json
+++ b/package.json
@@ -44,49 +44,49 @@
"@angular/platform-browser": "8.2.14",
"@angular/platform-browser-dynamic": "8.2.14",
"@angular/router": "8.2.14",
- "@babylonjs/core": "4.1.0-beta.12",
- "@babylonjs/materials": "4.1.0-beta.12",
+ "@babylonjs/core": "4.1.0-beta.20",
+ "@babylonjs/materials": "4.1.0-beta.20",
"@ngrx/effects": "8.6.0",
"@ngrx/store": "8.6.0",
- "@nrwl/angular": "8.9.0",
- "core-js": "3.6.0",
+ "@nrwl/angular": "8.11.0",
"hammerjs": "2.0.8",
"mnemonist": "0.32.0",
- "rxjs": "6.5.3",
+ "rxjs": "6.5.4",
"zone.js": "0.10.2"
},
"devDependencies": {
- "@angular-devkit/build-angular": "0.803.21",
- "@angular/cli": "8.3.21",
+ "@angular-devkit/build-angular": "0.803.22",
+ "@angular/cli": "8.3.22",
"@angular/compiler-cli": "8.2.14",
"@angular/language-service": "8.2.14",
- "@babylonjs/inspector": "4.1.0-beta.12",
- "@nrwl/cypress": "8.9.0",
- "@nrwl/jest": "8.9.0",
- "@nrwl/node": "8.9.0",
- "@nrwl/workspace": "8.9.0",
+ "@babylonjs/inspector": "4.1.0-beta.20",
+ "@nrwl/cypress": "8.11.0",
+ "@nrwl/jest": "8.11.0",
+ "@nrwl/node": "8.11.0",
+ "@nrwl/workspace": "8.11.0",
"@types/benchmark": "1.0.31",
- "@types/jest": "24.0.24",
- "@types/node": "12.12.21",
- "babylonjs": "4.1.0-beta.12",
+ "@types/jest": "24.9.0",
+ "@types/node": "13.1.7",
+ "babylonjs": "4.1.0-beta.20",
"benchmark": "2.1.4",
"codelyzer": "5.2.1",
- "cypress": "3.7.0",
+ "cypress": "3.8.2",
"dotenv": "8.2.0",
- "gh-pages": "2.1.1",
+ "gh-pages": "2.2.0",
+ "handlebars": "4.7.2",
"jasmine-marbles": "0.6.0",
"jest": "24.9.0",
"jest-junit": "10.0.0",
"jest-preset-angular": "7.1.1",
"junit-xml": "1.2.0",
"prettier": "1.19.1",
- "stylelint": "12.0.0",
+ "stylelint": "13.0.0",
"stylelint-config-recommended": "3.0.0",
"stylelint-config-recommended-scss": "4.1.0",
"stylelint-config-standard": "19.0.0",
"stylelint-scss": "3.13.0",
- "ts-jest": "24.2.0",
- "ts-node": "8.5.4",
+ "ts-jest": "24.3.0",
+ "ts-node": "8.6.2",
"tslint": "5.20.1",
"typescript": "3.5.3"
}
diff --git a/tsconfig.json b/tsconfig.json
index 79137cd9..5139f576 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,26 +1,27 @@
{
"compileOnSave": false,
"compilerOptions": {
- "rootDir": ".",
- "sourceMap": true,
+ "baseUrl": ".",
"declaration": false,
- "moduleResolution": "node",
"emitDecoratorMetadata": true,
"esModuleInterop": true,
"experimentalDecorators": true,
"importHelpers": true,
- "target": "es2015",
- "module": "esnext",
- "typeRoots": ["node_modules/@types"],
"lib": ["es2017", "dom"],
- "skipLibCheck": true,
- "skipDefaultLibCheck": true,
- "baseUrl": ".",
+ "module": "esnext",
+ "moduleResolution": "node",
"paths": {
"@talus/ui": ["libs/ui/src/index.ts"],
"@talus/math": ["libs/math/src/index.ts"],
"@talus/vdb": ["libs/vdb/src/index.ts"]
- }
+ },
+ "rootDir": ".",
+ "skipDefaultLibCheck": true,
+ "skipLibCheck": true,
+ "sourceMap": true,
+ "strictNullChecks": true,
+ "target": "es2015",
+ "typeRoots": ["node_modules/@types"]
},
"exclude": ["node_modules", "tmp"]
}
diff --git a/yarn.lock b/yarn.lock
index 1d45ac82..b8e310aa 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -10,31 +10,31 @@
"@angular-devkit/core" "8.3.14"
rxjs "6.4.0"
-"@angular-devkit/architect@0.803.21":
- version "0.803.21"
- resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.803.21.tgz#0e76b6f646ebdbd9bb88d3972b2ca66fed950f7d"
- integrity sha512-E2K/YexIWVyKM/xmyxvDjkJf+wX9u4c8YYpNaK4htsRzA06juc7N1MhlL/jURZiRl5b/K9sapYeq3tMX76saxA==
+"@angular-devkit/architect@0.803.22":
+ version "0.803.22"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/architect/-/architect-0.803.22.tgz#33b54099298aaef5f93ffefb8b91a98ea9f85387"
+ integrity sha512-5Gr0LH+Hjd/NLdmi660VBoo3WbzQM7/yeG+ziktb7hbeVaYK4Mejtcg/DJnCoZ3hzlZuZokWVwvpdFo+A9xKbg==
dependencies:
- "@angular-devkit/core" "8.3.21"
+ "@angular-devkit/core" "8.3.22"
rxjs "6.4.0"
-"@angular-devkit/build-angular@0.803.21":
- version "0.803.21"
- resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.803.21.tgz#f3d12ea09748b05eb2d835a7de7997599fb6b752"
- integrity sha512-flfgflvfpwdsm3x/U7QnfbtyZPEbsVipzQAoao1Zo58Beq1a+NsKsWbjrF/x4TSoI2czt0OVWXNytlfXM7LMhg==
+"@angular-devkit/build-angular@0.803.22":
+ version "0.803.22"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/build-angular/-/build-angular-0.803.22.tgz#0fa668e84c237c6b1ab524e50b0ccaedc3a92929"
+ integrity sha512-2q9qLsD52D4GACUAuQhvkgQ7vLAhZzdU0jzfs74RTxqUZ3PS6Ltrrwpdg2kp9RlQ53+nSCYjWBDLk1CxoEt4pg==
dependencies:
- "@angular-devkit/architect" "0.803.21"
- "@angular-devkit/build-optimizer" "0.803.21"
- "@angular-devkit/build-webpack" "0.803.21"
- "@angular-devkit/core" "8.3.21"
+ "@angular-devkit/architect" "0.803.22"
+ "@angular-devkit/build-optimizer" "0.803.22"
+ "@angular-devkit/build-webpack" "0.803.22"
+ "@angular-devkit/core" "8.3.22"
"@babel/core" "7.7.5"
"@babel/preset-env" "7.7.6"
- "@ngtools/webpack" "8.3.21"
+ "@ngtools/webpack" "8.3.22"
ajv "6.10.2"
autoprefixer "9.6.1"
- browserslist "4.6.6"
+ browserslist "4.8.3"
cacache "12.0.2"
- caniuse-lite "1.0.30000989"
+ caniuse-lite "1.0.30001019"
circular-dependency-plugin "5.2.0"
clean-css "4.2.1"
copy-webpack-plugin "5.1.1"
@@ -80,10 +80,10 @@
webpack-subresource-integrity "1.1.0-rc.6"
worker-plugin "3.2.0"
-"@angular-devkit/build-optimizer@0.803.21":
- version "0.803.21"
- resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.803.21.tgz#ecb3b6bba4b13ffbfbdbefb5997f690aa3635203"
- integrity sha512-gNN6kPaF4phZco3TmsrNr9tIEKXYsoSeoaUiDUfgmCYwa7fAqM8Ojh7HX6IQuB2PpVmEwKGlCcSh6xDtB33NjA==
+"@angular-devkit/build-optimizer@0.803.22":
+ version "0.803.22"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/build-optimizer/-/build-optimizer-0.803.22.tgz#6d09cbb5fd28ab7bd22ddc54e938f305dfff8b20"
+ integrity sha512-VIDeQcBn88PjHBTen3BRVA7DJiKEJdDwukx61mUvUDOcY7S5Ot5WqG0nrZifRjha17Z+fl3XuwS9TZNYmlF7WQ==
dependencies:
loader-utils "1.2.3"
source-map "0.7.3"
@@ -100,13 +100,13 @@
"@angular-devkit/core" "8.3.14"
rxjs "6.4.0"
-"@angular-devkit/build-webpack@0.803.21":
- version "0.803.21"
- resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.803.21.tgz#fd45754c0123f44fcde8fa6411ebea52d98054f0"
- integrity sha512-zCFVla/Xdk8qGVybvnHtoKml2h0/ShasSjT55VNZO1XaTCMqYkQEwwqSGEiVajpauafWjKrKxxBhsmWoI4efAA==
+"@angular-devkit/build-webpack@0.803.22":
+ version "0.803.22"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/build-webpack/-/build-webpack-0.803.22.tgz#079b2ded794308b2dc93769406bdb0a1e32015c0"
+ integrity sha512-RDLAhKHfTFzthzeawHEefYB1MxHiU2I32QzXI3XTCpR2XySw5JG9jIVIcsyDHQH1JtIfpHGq8vgfiTsE3r0YWA==
dependencies:
- "@angular-devkit/architect" "0.803.21"
- "@angular-devkit/core" "8.3.21"
+ "@angular-devkit/architect" "0.803.22"
+ "@angular-devkit/core" "8.3.22"
rxjs "6.4.0"
"@angular-devkit/core@8.3.14":
@@ -120,10 +120,10 @@
rxjs "6.4.0"
source-map "0.7.3"
-"@angular-devkit/core@8.3.21":
- version "8.3.21"
- resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-8.3.21.tgz#447022813e46333e930816c287722d06b9c4dd3a"
- integrity sha512-BYyVbrbys535FplX0+GVOlYBg/cyk1U5SRhSxRRFZYi9epVlEBBPk8/6wV4cQPGb6EwXkVj7YtPWXjXcGfzWmA==
+"@angular-devkit/core@8.3.22":
+ version "8.3.22"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/core/-/core-8.3.22.tgz#085cc1cf356cec00d0a1cea83ef1f21277f5ff55"
+ integrity sha512-lOEYcvK3MktjR9YZT/cUjiQE5dZxl8rZ/vgWgwDiL7RtzfXTt8lPapoJe7YKS53gLbUYiBNPCtTyTAqnslWgGA==
dependencies:
ajv "6.10.2"
fast-json-stable-stringify "2.0.0"
@@ -139,12 +139,12 @@
"@angular-devkit/core" "8.3.14"
rxjs "6.4.0"
-"@angular-devkit/schematics@8.3.21":
- version "8.3.21"
- resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-8.3.21.tgz#80d515f480180be18a4130ea691f90153bcab3ea"
- integrity sha512-+wH0362CRr/SijVX4w2baY2ANZ4scQ1k2xO8lT+NMeZQkw3IJQPOfwk1IaqiAs2xuBJZcSDH1Gn80+Jh4Dit7w==
+"@angular-devkit/schematics@8.3.22":
+ version "8.3.22"
+ resolved "https://registry.yarnpkg.com/@angular-devkit/schematics/-/schematics-8.3.22.tgz#41461768cc6cf54708d55311e59b9defa7bff484"
+ integrity sha512-ETLdV1ftT+ZuuiHl6FjFQ4XLQznWMcxWognX+qgByn+DQOXsYRRvZK1L5eG/SG8CKJ8NL5oteTDloDnghARHFw==
dependencies:
- "@angular-devkit/core" "8.3.21"
+ "@angular-devkit/core" "8.3.22"
rxjs "6.4.0"
"@angular-eslint/builder@0.0.1-alpha.17":
@@ -168,16 +168,16 @@
optionalDependencies:
parse5 "^5.0.0"
-"@angular/cli@8.3.21":
- version "8.3.21"
- resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-8.3.21.tgz#cbb05b86b7f34ecd81d52ccad922359e66a16a15"
- integrity sha512-ZZpA7mMfIobFT06rBNxm8vucAh8W2s0huJZ4iL0BPujnhIr71PL+gDwssySWDEz2q6i4CkH9QRH76DHhtL6VSQ==
+"@angular/cli@8.3.22":
+ version "8.3.22"
+ resolved "https://registry.yarnpkg.com/@angular/cli/-/cli-8.3.22.tgz#2512e0aeaffdbb30ace35dc288eeba9a86f28b95"
+ integrity sha512-OT2rzwnxwI0ETP7rXCxjxsIAZEYo9wHP/5rRbu3m15GlQ3Bclq34ZDRwC/bRxXL5+1DfmhAs9AjtYNoFoDM4Tg==
dependencies:
- "@angular-devkit/architect" "0.803.21"
- "@angular-devkit/core" "8.3.21"
- "@angular-devkit/schematics" "8.3.21"
- "@schematics/angular" "8.3.21"
- "@schematics/update" "0.803.21"
+ "@angular-devkit/architect" "0.803.22"
+ "@angular-devkit/core" "8.3.22"
+ "@angular-devkit/schematics" "8.3.22"
+ "@schematics/angular" "8.3.22"
+ "@schematics/update" "0.803.22"
"@yarnpkg/lockfile" "1.1.0"
ansi-colors "4.1.1"
debug "^4.1.1"
@@ -1534,58 +1534,58 @@
lodash "^4.17.13"
to-fast-properties "^2.0.0"
-"@babylonjs/core@4.1.0-beta.12":
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/@babylonjs/core/-/core-4.1.0-beta.12.tgz#9aaaa51fa4fc72defb9e444d8376294f3bccbb0b"
- integrity sha512-o5IUXJJWwZpON4YRytvYJkdhuKVf5Kf8bieotp4TVqo+ECB+mUGvxkDFoa/Mc1A0QLT7YcDSuibYQbu6asRrTQ==
+"@babylonjs/core@4.1.0-beta.20":
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/@babylonjs/core/-/core-4.1.0-beta.20.tgz#fa554a10127e9409bec56b5c77256374b0524390"
+ integrity sha512-vKVaRNTGz/SgOljfhRhSJaAKajjkoXQQE5AgtdUz6zc4ps+9YPqV4sIFTS8jCSREnlnwpyLe7F8MjVYw4O51Aw==
dependencies:
tslib "^1.10.0"
-"@babylonjs/gui@4.1.0-beta.12":
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/@babylonjs/gui/-/gui-4.1.0-beta.12.tgz#b467209fde28479e340dd0db107736b0334ae6a3"
- integrity sha512-7WjS0liqvtSnJKqCR3ft2cwyOlqFiAUDQwzsSax4f1Iq9ql4M5J5+LC0FLXgkAGiltut8JjioSdEG39kD3T0TA==
+"@babylonjs/gui@4.1.0-beta.20":
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/@babylonjs/gui/-/gui-4.1.0-beta.20.tgz#20933a191eb8ec6b1c49c809eea5af0f9da62856"
+ integrity sha512-dxLiAvfrgqaE+LMaulcpb40VYe2VIgWjf/SrHKPNnV7SY9dvaxBjqH7+1J7E8zO0e3n8i6nFuUWZ9ij2lKcGsQ==
dependencies:
- "@babylonjs/core" "4.1.0-beta.12"
+ "@babylonjs/core" "4.1.0-beta.20"
tslib "^1.10.0"
-"@babylonjs/inspector@4.1.0-beta.12":
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/@babylonjs/inspector/-/inspector-4.1.0-beta.12.tgz#c2e489b2a6a29d65523eec93a44346b1e65c97ec"
- integrity sha512-Wga2Q5Gu5CBiR3zNMV30hCeTlDt5DxOGogOmMlkU9IfXg84VcpgjjHa4a1NV/nDaJtOP+sANKIvxVyAgtMhhhQ==
- dependencies:
- "@babylonjs/core" "4.1.0-beta.12"
- "@babylonjs/gui" "4.1.0-beta.12"
- "@babylonjs/loaders" "4.1.0-beta.12"
- "@babylonjs/materials" "4.1.0-beta.12"
- "@babylonjs/serializers" "4.1.0-beta.12"
- babylonjs-gltf2interface "4.1.0-beta.12"
+"@babylonjs/inspector@4.1.0-beta.20":
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/@babylonjs/inspector/-/inspector-4.1.0-beta.20.tgz#79224464a772bcf470c3ef352d117560a771356d"
+ integrity sha512-aonk4bArPhZ+HPj5J13BAyqD/QHBxcAr4oZZgim2DQXjuC40f6ClUYRQH/p0hPJYoy3uR0GiTOvWxx/MPhCOiQ==
+ dependencies:
+ "@babylonjs/core" "4.1.0-beta.20"
+ "@babylonjs/gui" "4.1.0-beta.20"
+ "@babylonjs/loaders" "4.1.0-beta.20"
+ "@babylonjs/materials" "4.1.0-beta.20"
+ "@babylonjs/serializers" "4.1.0-beta.20"
+ babylonjs-gltf2interface "4.1.0-beta.20"
tslib "^1.10.0"
-"@babylonjs/loaders@4.1.0-beta.12":
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/@babylonjs/loaders/-/loaders-4.1.0-beta.12.tgz#a0225a705507705ca9d4730eede87c95aa4b84c7"
- integrity sha512-FIZxjltGLMP3DSCtos365HjPpL7zOfzkERe+X5/yy9zkMKPrzZGcKv90MZyEx+9lrjMTV3sueDMNTnp6d9pc/g==
+"@babylonjs/loaders@4.1.0-beta.20":
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/@babylonjs/loaders/-/loaders-4.1.0-beta.20.tgz#31c910fb5f72a3049688181c7c0ffbdd519e8f4e"
+ integrity sha512-zNqCjb9vR4oArVaOPMqnKMQFzRe3gw0aSY56oBfMisfcwilWRD9Dcc9dy4gn7m5VgPUTIMtMrBfRnrDerNK1yA==
dependencies:
- "@babylonjs/core" "4.1.0-beta.12"
- babylonjs-gltf2interface "4.1.0-beta.12"
+ "@babylonjs/core" "4.1.0-beta.20"
+ babylonjs-gltf2interface "4.1.0-beta.20"
tslib "^1.10.0"
-"@babylonjs/materials@4.1.0-beta.12":
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/@babylonjs/materials/-/materials-4.1.0-beta.12.tgz#71dfe537b54c243e8c7db0a46683986c6d284008"
- integrity sha512-lwJ6SZySiQiT+dijkg3yddgU71sGzmiO2Zm8JzSsRJkuA2P6K8s1sZUDVAhI5h6Im8i7LiSFWLPQQjZsDaOAkA==
+"@babylonjs/materials@4.1.0-beta.20":
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/@babylonjs/materials/-/materials-4.1.0-beta.20.tgz#67a3368a894ffa645999a068f995c0802497a7c1"
+ integrity sha512-uQSaFdQAKdZC/9CLEufvDyQ37SsPC2zuZt9awugB20tRCsYuj0q6FWmrGR+hleVsOoq/xm9e8y0vnf1Kx9F5bg==
dependencies:
- "@babylonjs/core" "4.1.0-beta.12"
+ "@babylonjs/core" "4.1.0-beta.20"
tslib "^1.10.0"
-"@babylonjs/serializers@4.1.0-beta.12":
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/@babylonjs/serializers/-/serializers-4.1.0-beta.12.tgz#0c5f6a0050af4a6b7384a6d3dcb34a8f496ea58a"
- integrity sha512-T2YWPPgj6voKowx9YanPTaFqPatxfBR3oVm/uPtt2iRFvt8POy1wYWBBzjFHRJKicQflhA2LEfHWFr82xyzCCg==
+"@babylonjs/serializers@4.1.0-beta.20":
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/@babylonjs/serializers/-/serializers-4.1.0-beta.20.tgz#9ce3f3661c9d4246c1215a97482df1d86c3a12ef"
+ integrity sha512-BWMXr0DxGC1hNOiDaQ2FKlueBP3bdFTs98uoo+sWarKhiaOwKkast8DF7QZnEyZVR6oPvUr06FEYmWZnVgidQg==
dependencies:
- "@babylonjs/core" "4.1.0-beta.12"
- babylonjs-gltf2interface "4.1.0-beta.12"
+ "@babylonjs/core" "4.1.0-beta.20"
+ babylonjs-gltf2interface "4.1.0-beta.20"
tslib "^1.10.0"
"@cnakazawa/watch@^1.0.3":
@@ -1774,14 +1774,6 @@
"@types/istanbul-reports" "^1.1.1"
"@types/yargs" "^13.0.0"
-"@mrmlnc/readdir-enhanced@^2.2.1":
- version "2.2.1"
- resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde"
- integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g==
- dependencies:
- call-me-maybe "^1.0.1"
- glob-to-regexp "^0.3.0"
-
"@ngrx/effects@8.6.0":
version "8.6.0"
resolved "https://registry.yarnpkg.com/@ngrx/effects/-/effects-8.6.0.tgz#a0d7339597a5128c5cf896ddcf93f73406a45860"
@@ -1792,48 +1784,64 @@
resolved "https://registry.yarnpkg.com/@ngrx/store/-/store-8.6.0.tgz#8540c5bd40b33fc2f443e7e86f47c0d801b8f413"
integrity sha512-K4cvCEa+5hw9qrETQWO+Cha3YbVCAT8yaIKJr/N35KntTL9mQMjoL+51JWLZfBwPV0e19CFgJIyrBnVUTxwr2A==
-"@ngtools/webpack@8.3.21":
- version "8.3.21"
- resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-8.3.21.tgz#d28f2b66a8aeced5260c42ae722192ec5d5e4e56"
- integrity sha512-DGqmFQ52sV4uB3y3spQTNLa69oU5cwd1yIqMB4GSM+Qp+hozdzrPA2gVH90N2DDhWe8icsSQHAtZQiR9+BDL8g==
+"@ngtools/webpack@8.3.22":
+ version "8.3.22"
+ resolved "https://registry.yarnpkg.com/@ngtools/webpack/-/webpack-8.3.22.tgz#f6792d66430fb48c890a8145dee5088e3519860b"
+ integrity sha512-MES7Q0k6GpQEY74cxElUVy7jIaDBSLvY+eOUN2GKL5CznvBSp3+U5px6X7ZjPGzCp7no1L1JkV9g2e0hPatlcw==
dependencies:
- "@angular-devkit/core" "8.3.21"
+ "@angular-devkit/core" "8.3.22"
enhanced-resolve "4.1.0"
rxjs "6.4.0"
tree-kill "1.2.1"
webpack-sources "1.4.3"
-"@nodelib/fs.stat@^1.1.2":
- version "1.1.3"
- resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b"
- integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw==
+"@nodelib/fs.scandir@2.1.3":
+ version "2.1.3"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.scandir/-/fs.scandir-2.1.3.tgz#3a582bdb53804c6ba6d146579c46e52130cf4a3b"
+ integrity sha512-eGmwYQn3gxo4r7jdQnkrrN6bY478C3P+a/y72IJukF8LjB6ZHeB3c+Ehacj3sYeSmUXGlnA67/PmbM9CVwL7Dw==
+ dependencies:
+ "@nodelib/fs.stat" "2.0.3"
+ run-parallel "^1.1.9"
+
+"@nodelib/fs.stat@2.0.3", "@nodelib/fs.stat@^2.0.2":
+ version "2.0.3"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.3.tgz#34dc5f4cabbc720f4e60f75a747e7ecd6c175bd3"
+ integrity sha512-bQBFruR2TAwoevBEd/NWMoAAtNGzTRgdrqnYCc7dhzfoNvqPzLyqlEQnzZ3kVnNrSp25iyxE00/3h2fqGAGArA==
-"@nrwl/angular@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/angular/-/angular-8.9.0.tgz#54b5bf31d969a8cd8a49f9e1a112f3d0fa7ac437"
- integrity sha512-FxMKD3g5JQ3LwInRv1Pa8X1efG/nSoeBOTMbtEJs7CnaTonMWMPbY8QNSFidM8J+dWxOMDs9DXm5v66eOELpnw==
+"@nodelib/fs.walk@^1.2.3":
+ version "1.2.4"
+ resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.4.tgz#011b9202a70a6366e436ca5c065844528ab04976"
+ integrity sha512-1V9XOY4rDW0rehzbrcqAmHnz8e7SKvX27gh8Gt2WgB0+pdzdiLV83p72kZPU+jvMbS1qU5mauP2iOvO8rhmurQ==
+ dependencies:
+ "@nodelib/fs.scandir" "2.1.3"
+ fastq "^1.6.0"
+
+"@nrwl/angular@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/angular/-/angular-8.11.0.tgz#d65f8800acb852544fec4b11b0b49fe12bbb34b3"
+ integrity sha512-MIFwd2WdY8uvW1oySPzGxs2kYtprXIHYzXkkW3L5BMY0yVWTUqpUpmtMHQBPgA2E2OCIIO7jpccrXMRofMU57Q==
dependencies:
"@angular-devkit/schematics" "8.3.14"
- "@nrwl/cypress" "8.9.0"
- "@nrwl/jest" "8.9.0"
+ "@nrwl/cypress" "8.11.0"
+ "@nrwl/jest" "8.11.0"
"@schematics/angular" "8.3.14"
jasmine-marbles "~0.6.0"
-"@nrwl/cli@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/cli/-/cli-8.9.0.tgz#5553d01909b75efc43e24ee3d5781243fbacbc9a"
- integrity sha512-Z2ci9BQNsPeBfJTpXwMJ9NIfMLTEMsPoOXGxlCTjTZcpr6t2TlScVR9BIArgrv4BiMctyKUFRBxe6aX9eO98KA==
+"@nrwl/cli@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/cli/-/cli-8.11.0.tgz#bb45b31c45409af706b2636798ec695a2c6104aa"
+ integrity sha512-S8z9wgeWObmRuCXWVrQ9yIeWnyJJ4CEIzmuSbs3k+XBx/MTP2QsoluJSYHv4NYxFM2hTboZPNuicNsz16Ua5/Q==
dependencies:
- "@nrwl/tao" "8.9.0"
+ "@nrwl/tao" "8.11.0"
chalk "2.4.2"
tmp "0.0.33"
yargs "^11.0.0"
yargs-parser "10.0.0"
-"@nrwl/cypress@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/cypress/-/cypress-8.9.0.tgz#90016e1f9f4442436e5c3ce65d30923355d22210"
- integrity sha512-xVTp5Lyy2HRYqJn3xwFJ85bzJiDygKuSm7ZXKJojCqg4ZwCBJDOoE3GzT/gYs1jRrKhV/jizkXkNtJA1UK2HZQ==
+"@nrwl/cypress@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/cypress/-/cypress-8.11.0.tgz#d0771f9a5f4e1cb25c7230de6372d3da9d9adcf0"
+ integrity sha512-AB8Df+eX/qTR05EDswhk1hr9/RxNBe41mUzUq3KGvXEj7xMw+6Jt3JmBnoISk2olqDTB1DM3gLV0ytSC1FkktQ==
dependencies:
"@angular-devkit/architect" "0.803.14"
"@angular-devkit/core" "8.3.14"
@@ -1843,37 +1851,37 @@
tsconfig-paths-webpack-plugin "3.2.0"
webpack-node-externals "1.7.2"
-"@nrwl/jest@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/jest/-/jest-8.9.0.tgz#be8d07c0c3b10d918e119eaa8b51a14013c3cb97"
- integrity sha512-Vi10aiIAsNb5xqedyPT173nQLhblfFZG/GleO+SkM9qXjRLm6n1KgFdiLuOI5V+mtU0UcCSd+SbI2uJsk19i2w==
+"@nrwl/jest@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/jest/-/jest-8.11.0.tgz#ed02e7facc90c91bff0f6974a3d329d1e83ca9f4"
+ integrity sha512-EyuuNAItQDSwJNtsDTs7zINdRG9GjU2rnTJsonMdnsdZIikM0HD8xooF/XzdIqfbc5c7ZZ46LqCChQ8PhWqBhQ==
dependencies:
"@angular-devkit/architect" "0.803.14"
"@angular-devkit/core" "8.3.14"
"@angular-devkit/schematics" "8.3.14"
-"@nrwl/linter@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/linter/-/linter-8.9.0.tgz#260a7ccaf9cc951042f5c23f480114a20794e0b8"
- integrity sha512-e4mkAaR6BrgPWxw8YMhvuhIQUl7epm7rDnriZ3Y93DF/tfFNh5R5Hy57Nix52NDlnjP6kVcf2lxvrPSUi4iyrA==
+"@nrwl/linter@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/linter/-/linter-8.11.0.tgz#9113d574dabfedda4059b8130e1299a95b4169c6"
+ integrity sha512-a66Hx84XJZTziiVNyqoan1lhcI10NFLfta0Sgk+9gGHuaT4KI3NjAhKSUNSchIlyN8enRb+Gl3Wenv2CHnqyJw==
dependencies:
"@angular-devkit/architect" "0.803.14"
"@angular-eslint/builder" "0.0.1-alpha.17"
-"@nrwl/node@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/node/-/node-8.9.0.tgz#91f7770053f67672fa53d207b0fa57220c147da4"
- integrity sha512-wCKLdeUnlohPJ7B4m3YUrn727i7simRzeByfHbslxnY85U0PmbVkOZXs6RlQxAh0dErNAbDfgN+vRPESVn9Eng==
+"@nrwl/node@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/node/-/node-8.11.0.tgz#8e21f869ef4b9139cc9bed0ae6ee19802f11888f"
+ integrity sha512-H4LXQO1TYn5XjTo5bEySzuNSzu/gIffWbm4DHX9Ilie2iRr1fBDLD+/oo5qNLGhLuFWM8o9gKG6FDpNAhI7B6g==
dependencies:
"@angular-devkit/architect" "0.803.14"
"@angular-devkit/build-webpack" "0.803.14"
"@angular-devkit/core" "8.3.14"
"@angular-devkit/schematics" "8.3.14"
- "@nrwl/jest" "8.9.0"
- "@nrwl/linter" "8.9.0"
+ "@nrwl/jest" "8.11.0"
+ "@nrwl/linter" "8.11.0"
circular-dependency-plugin "5.2.0"
- copy-webpack-plugin "5.0.3"
- fork-ts-checker-webpack-plugin "0.4.15"
+ copy-webpack-plugin "5.1.1"
+ fork-ts-checker-webpack-plugin "^3.1.1"
license-webpack-plugin "2.1.2"
source-map-support "0.5.12"
tree-kill "1.2.1"
@@ -1881,12 +1889,13 @@
tsconfig-paths-webpack-plugin "3.2.0"
webpack "4.41.2"
webpack-dev-server "3.9.0"
+ webpack-merge "4.2.1"
webpack-node-externals "1.7.2"
-"@nrwl/tao@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-8.9.0.tgz#f28a8a62e2613d30805fd85f2e9234fb01d39133"
- integrity sha512-hAIw7J94qv+i+JMs6aB0ZS/eBOlYJ0L50VeaFWk2n94FmDNW4WFKIQRuNBM4CGcdpT+h1z3tR7QeWPjCaXk3Ow==
+"@nrwl/tao@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/tao/-/tao-8.11.0.tgz#bf03d8825cccb06a7fd7d7c498b278deda882f78"
+ integrity sha512-9N+Vk/M8u1XVjMiLvtjEeFXYkb1TfSFvlKR0XyY7arCYmA/a6z594D4nUADjpDogNy2cyxBXcAjkKTOK1FSqZw==
dependencies:
"@angular-devkit/architect" "0.803.14"
"@angular-devkit/core" "8.3.14"
@@ -1896,21 +1905,21 @@
minimist "^1.2.0"
strip-json-comments "2.0.1"
-"@nrwl/workspace@8.9.0":
- version "8.9.0"
- resolved "https://registry.yarnpkg.com/@nrwl/workspace/-/workspace-8.9.0.tgz#4dc3d1ff9b34ce983158a5aa4bf3a0ef28c0df69"
- integrity sha512-mwimmwx1V5kO9DXVygw++PoRhyIrut+LSQ3VGWu+ui9qwNQlcCLPwQQdHHp447qGdcb8Qne9ZPMHXUt8sWo5EQ==
+"@nrwl/workspace@8.11.0":
+ version "8.11.0"
+ resolved "https://registry.yarnpkg.com/@nrwl/workspace/-/workspace-8.11.0.tgz#42b37098db2ad31047db1907169f6969907feee1"
+ integrity sha512-3cougMUedrOO8v1164i6I+mrGyDm1Uv2yFrYwMAnAcW+9s9Yy2KgEJ4HyBb4rJIhi7uKyQk9u9Q9QQtJsW+Kjg==
dependencies:
"@angular-devkit/core" "8.3.14"
"@angular-devkit/schematics" "8.3.14"
- "@nrwl/cli" "8.9.0"
+ "@nrwl/cli" "8.11.0"
chalk "2.4.2"
cosmiconfig "4.0.0"
fs-extra "6.0.0"
+ hasha "5.1.0"
ignore "5.0.4"
npm-run-all "4.1.5"
opn "^5.3.0"
- prettier "1.18.2"
rxjs "^6.4.0"
semver "5.4.1"
strip-json-comments "2.0.1"
@@ -1926,21 +1935,21 @@
"@angular-devkit/core" "8.3.14"
"@angular-devkit/schematics" "8.3.14"
-"@schematics/angular@8.3.21":
- version "8.3.21"
- resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-8.3.21.tgz#4902e0b6e8be47006859009bf96a026e3d39dd27"
- integrity sha512-KahQ+dHvTsGOZwY6IdzqJZLDEn0G89rrK3OY+7okZujoaLM+LXhxlPoznW1udnZJVTa3VNxYGx11fkgLtRJRqA==
+"@schematics/angular@8.3.22":
+ version "8.3.22"
+ resolved "https://registry.yarnpkg.com/@schematics/angular/-/angular-8.3.22.tgz#fab009312bd3d50115332f2c41a92e15744ac09f"
+ integrity sha512-vD+UgPdbEoFPOH6xe2laFpHn/MC9R5C4A/+J9yQ6HBg5kt1YdyIBakvPOcXQCyWr5VZzDmTyMO76rd3zaef3DQ==
dependencies:
- "@angular-devkit/core" "8.3.21"
- "@angular-devkit/schematics" "8.3.21"
+ "@angular-devkit/core" "8.3.22"
+ "@angular-devkit/schematics" "8.3.22"
-"@schematics/update@0.803.21":
- version "0.803.21"
- resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.803.21.tgz#572c955bb132348bca03a128491ae264b0068a0a"
- integrity sha512-D3BRvEBF2cJEgogvFaNOfqtTFHHv/ctSRfOeAYWjUxILtb+2DpuZ9h5QYDFhN9MPgz/vRaOqFORa3sEZCRkX4g==
+"@schematics/update@0.803.22":
+ version "0.803.22"
+ resolved "https://registry.yarnpkg.com/@schematics/update/-/update-0.803.22.tgz#88b2fd3c5c2e3c5b2f453b912b281df14c94fd34"
+ integrity sha512-X+1sJ7YadcYxDqcLX7l7MEAIL3SHIXpCqToQdAZbAE06NdTFvg5eqiKreSdmm7ZdfL0dBe6oXi/yCDVMoL2zcw==
dependencies:
- "@angular-devkit/core" "8.3.21"
- "@angular-devkit/schematics" "8.3.21"
+ "@angular-devkit/core" "8.3.22"
+ "@angular-devkit/schematics" "8.3.22"
"@yarnpkg/lockfile" "1.1.0"
ini "1.3.5"
pacote "9.5.5"
@@ -2025,10 +2034,10 @@
"@types/istanbul-lib-coverage" "*"
"@types/istanbul-lib-report" "*"
-"@types/jest@24.0.24":
- version "24.0.24"
- resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.0.24.tgz#0f2f523dc77cc1bc6bef34eaf287ede887a73f05"
- integrity sha512-vgaG968EDPSJPMunEDdZvZgvxYSmeH8wKqBlHSkBt1pV2XlLEVDzsj1ZhLuI4iG4Pv841tES61txSBF0obh4CQ==
+"@types/jest@24.9.0":
+ version "24.9.0"
+ resolved "https://registry.yarnpkg.com/@types/jest/-/jest-24.9.0.tgz#78c6991cd1734cf0d390be24875e310bb0a9fb74"
+ integrity sha512-dXvuABY9nM1xgsXlOtLQXJKdacxZJd7AtvLsKZ/0b57ruMXDKCOXAC/M75GbllQX6o1pcZ5hAG4JzYy7Z/wM2w==
dependencies:
jest-diff "^24.3.0"
@@ -2042,15 +2051,25 @@
resolved "https://registry.yarnpkg.com/@types/minimatch/-/minimatch-3.0.3.tgz#3dca0e3f33b200fc7d1139c0cd96c1268cadfd9d"
integrity sha512-tHq6qdbT9U1IRSGf14CL0pUlULksvY9OZ+5eEgl1N7t+OA3tGvNpxJCzuKQlsNgCVwbAs670L1vcVQi8j9HjnA==
+"@types/minimist@^1.2.0":
+ version "1.2.0"
+ resolved "https://registry.yarnpkg.com/@types/minimist/-/minimist-1.2.0.tgz#69a23a3ad29caf0097f06eda59b361ee2f0639f6"
+ integrity sha1-aaI6OtKcrwCX8G7aWbNh7i8GOfY=
+
"@types/node@*":
version "12.7.2"
resolved "https://registry.yarnpkg.com/@types/node/-/node-12.7.2.tgz#c4e63af5e8823ce9cc3f0b34f7b998c2171f0c44"
integrity sha512-dyYO+f6ihZEtNPDcWNR1fkoTDf3zAK3lAABDze3mz6POyIercH0lEUawUFXlG8xaQZmm1yEBON/4TsYv/laDYg==
-"@types/node@12.12.21":
- version "12.12.21"
- resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.21.tgz#aa44a6363291c7037111c47e4661ad210aded23f"
- integrity sha512-8sRGhbpU+ck1n0PGAUgVrWrWdjSW2aqNeyC15W88GRsMpSwzv6RJGlLhE7s2RhVSOdyDmxbqlWSeThq4/7xqlA==
+"@types/node@13.1.7":
+ version "13.1.7"
+ resolved "https://registry.yarnpkg.com/@types/node/-/node-13.1.7.tgz#db51d28b8dfacfe4fb2d0da88f5eb0a2eca00675"
+ integrity sha512-HU0q9GXazqiKwviVxg9SI/+t/nAsGkvLDkIdxz+ObejG2nX6Si00TeLqHMoS+a/1tjH7a8YpKVQwtgHuMQsldg==
+
+"@types/normalize-package-data@^2.4.0":
+ version "2.4.0"
+ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.0.tgz#e486d0d97396d79beedd0a6e33f4534ff6b4973e"
+ integrity sha512-f5j5b/Gf71L+dbqxIpQ4Z2WlmI/mPJ0fOkGGmFgtb6sAu97EPczzbS3/tJKxmcYDj55OX6ssqwDAWOHIYDRDGA==
"@types/parse-json@^4.0.0":
version "4.0.0"
@@ -2328,11 +2347,16 @@ acorn@^5.5.3:
resolved "https://registry.yarnpkg.com/acorn/-/acorn-5.7.3.tgz#67aa231bf8812974b85235a96771eb6bd07ea279"
integrity sha512-T/zvzYRfbVojPWahDsE5evJdHb3oJoQfFbsrKM7w5Zcs++Tr257tia3BmMP8XYVjp1S9RZXQMh7gao96BlqZOw==
-acorn@^6.0.1, acorn@^6.0.4, acorn@^6.2.1:
+acorn@^6.0.1, acorn@^6.2.1:
version "6.3.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.3.0.tgz#0087509119ffa4fc0a0041d1e93a417e68cb856e"
integrity sha512-/czfa8BwS88b9gWQVhc8eknunSA2DoJpJyTQkhheIf5E48u1N0R4q/YxxsAeqRrmK9TQ/uYfgLDfZo91UlANIA==
+acorn@^6.0.4:
+ version "6.4.0"
+ resolved "https://registry.yarnpkg.com/acorn/-/acorn-6.4.0.tgz#b659d2ffbafa24baf5db1cdbb2c94a983ecd2784"
+ integrity sha512-gac8OEcQ2Li1dxIEWGZzsp2BitJxwkwcOm0zHAJLcPJaVvm58FRnk6RkuLRpU1EujipU2ZFODv2P9DLMfnV8mw==
+
agent-base@4, agent-base@^4.3.0:
version "4.3.0"
resolved "https://registry.yarnpkg.com/agent-base/-/agent-base-4.3.0.tgz#8165f01c436009bccad0b1d122f05ed770efc6ee"
@@ -2477,6 +2501,14 @@ anymatch@^3.0.1:
normalize-path "^3.0.0"
picomatch "^2.0.4"
+anymatch@~3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/anymatch/-/anymatch-3.1.1.tgz#c55ecf02185e2469259399310c173ce31233b142"
+ integrity sha512-mM8522psRCqzV+6LhomX5wgp25YVibjh8Wj23I5RPkPppSVSjyKD2A2mBJmWGa+KN7f2D6LNh9jkBCeyLktzjg==
+ dependencies:
+ normalize-path "^3.0.0"
+ picomatch "^2.0.4"
+
app-root-path@^2.2.1:
version "2.2.1"
resolved "https://registry.yarnpkg.com/app-root-path/-/app-root-path-2.2.1.tgz#d0df4a682ee408273583d43f6f79e9892624bc9a"
@@ -2540,11 +2572,6 @@ array-equal@^1.0.0:
resolved "https://registry.yarnpkg.com/array-equal/-/array-equal-1.0.0.tgz#8c2a5ef2472fd9ea742b04c77a75093ba2757c93"
integrity sha1-jCpe8kcv2ep0KwTHenUJO6J1fJM=
-array-find-index@^1.0.1:
- version "1.0.2"
- resolved "https://registry.yarnpkg.com/array-find-index/-/array-find-index-1.0.2.tgz#df010aa1287e164bbda6f9723b0a96a1ec4187a1"
- integrity sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=
-
array-flatten@1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2"
@@ -2555,13 +2582,18 @@ array-flatten@^2.1.0:
resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-2.1.2.tgz#24ef80a28c1a893617e2149b0c6d0d788293b099"
integrity sha512-hNfzcOV8W4NdualtqBFPyVO+54DSJuZGY9qT4pRroB6S9e3iiido2ISIC5h9R2sPJ8H3FHCIiEnsv1lPXO3KtQ==
-array-union@^1.0.1, array-union@^1.0.2:
+array-union@^1.0.1:
version "1.0.2"
resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39"
integrity sha1-mjRBDk9OPaI96jdb5b5w8kd47Dk=
dependencies:
array-uniq "^1.0.1"
+array-union@^2.1.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d"
+ integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==
+
array-uniq@^1.0.1:
version "1.0.3"
resolved "https://registry.yarnpkg.com/array-uniq/-/array-uniq-1.0.3.tgz#af6ac877a25cc7f74e058894753858dfdb24fdb6"
@@ -2673,17 +2705,17 @@ autoprefixer@9.6.1:
postcss "^7.0.17"
postcss-value-parser "^4.0.0"
-autoprefixer@^9.7.1:
- version "9.7.2"
- resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.2.tgz#26cf729fbb709323b40171a874304884dcceffed"
- integrity sha512-LCAfcdej1182uVvPOZnytbq61AhnOZ/4JelDaJGDeNwewyU1AMaNthcHsyz1NRjTmd2FkurMckLWfkHg3Z//KA==
+autoprefixer@^9.7.3:
+ version "9.7.4"
+ resolved "https://registry.yarnpkg.com/autoprefixer/-/autoprefixer-9.7.4.tgz#f8bf3e06707d047f0641d87aee8cfb174b2a5378"
+ integrity sha512-g0Ya30YrMBAEZk60lp+qfX5YQllG+S5W3GYCFvyHTvhOki0AEQJLPEcIuGRsqVwLi8FvXPVtwTGhfr38hVpm0g==
dependencies:
- browserslist "^4.7.3"
- caniuse-lite "^1.0.30001010"
+ browserslist "^4.8.3"
+ caniuse-lite "^1.0.30001020"
chalk "^2.4.2"
normalize-range "^0.1.2"
num2fraction "^1.2.2"
- postcss "^7.0.23"
+ postcss "^7.0.26"
postcss-value-parser "^4.0.2"
aws-sign2@~0.7.0:
@@ -2837,15 +2869,15 @@ babylon@^6.18.0:
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
-babylonjs-gltf2interface@4.1.0-beta.12:
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/babylonjs-gltf2interface/-/babylonjs-gltf2interface-4.1.0-beta.12.tgz#38dbc4d3b48e76d4b29d9508092d62eb17e4ae26"
- integrity sha512-BOLX7C2elDVd9UtJXPnOF7qMCy7LebtpySCEnhlsZDvCIVWqBhQgzXA/d3Oeb4tGtpiZtaB87WG2bzuLWL0FzA==
+babylonjs-gltf2interface@4.1.0-beta.20:
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/babylonjs-gltf2interface/-/babylonjs-gltf2interface-4.1.0-beta.20.tgz#90368bda475b3857b3043913d6358f8c4604d05b"
+ integrity sha512-Y3hGTh+5Yhywc7k8p8n49KKk3Od8u9pSgIp4OOjxliGSuRtc301chifpfVThgcs7UVoowfCXXxdB6mrUzRnFXw==
-babylonjs@4.1.0-beta.12:
- version "4.1.0-beta.12"
- resolved "https://registry.yarnpkg.com/babylonjs/-/babylonjs-4.1.0-beta.12.tgz#f42d88d865c9ba984506afde3b054dec215af092"
- integrity sha512-SyQVqarSuBDAmIkIzGctb35XSwuRAv+vI9CaE5rz4ls35pbvPdj0Nf3sZUePUDw6CZueRp3z2sL+zgPuvbg3Ow==
+babylonjs@4.1.0-beta.20:
+ version "4.1.0-beta.20"
+ resolved "https://registry.yarnpkg.com/babylonjs/-/babylonjs-4.1.0-beta.20.tgz#46ce13e315f37e98d8930c561f49f81761b6c704"
+ integrity sha512-FU52D50wsS3Gr/VXWmLEKAqCOA4tuw+BIPJWnCaKmTN644k9IKyzOsZnMz+WulyC29Uce3duUKgv+PCpRMCKig==
bail@^1.0.0:
version "1.0.4"
@@ -2977,7 +3009,7 @@ braces@^2.3.1, braces@^2.3.2:
split-string "^3.0.2"
to-regex "^3.0.1"
-braces@^3.0.1, braces@^3.0.2:
+braces@^3.0.1, braces@^3.0.2, braces@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107"
integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==
@@ -3060,7 +3092,16 @@ browserify-zlib@^0.2.0:
dependencies:
pako "~1.0.5"
-browserslist@4.6.6, browserslist@^4.6.0, browserslist@^4.6.3, browserslist@^4.6.6:
+browserslist@4.8.3, browserslist@^4.8.3:
+ version "4.8.3"
+ resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.3.tgz#65802fcd77177c878e015f0e3189f2c4f627ba44"
+ integrity sha512-iU43cMMknxG1ClEZ2MDKeonKE1CCrFVkQK2AqO2YWFmvIrx4JWrvQ4w4hQez6EpVI8rHTtqh/ruHHDHSOKxvUg==
+ dependencies:
+ caniuse-lite "^1.0.30001017"
+ electron-to-chromium "^1.3.322"
+ node-releases "^1.1.44"
+
+browserslist@^4.6.0, browserslist@^4.6.3, browserslist@^4.6.6:
version "4.6.6"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.6.6.tgz#6e4bf467cde520bc9dbdf3747dafa03531cec453"
integrity sha512-D2Nk3W9JL9Fp/gIcWei8LrERCS+eXu9AM5cfXA8WEZ84lFks+ARnZ0q/R69m2SV3Wjma83QDDPxsNKXUwdIsyA==
@@ -3069,15 +3110,6 @@ browserslist@4.6.6, browserslist@^4.6.0, browserslist@^4.6.3, browserslist@^4.6.
electron-to-chromium "^1.3.191"
node-releases "^1.1.25"
-browserslist@^4.7.3:
- version "4.7.3"
- resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.7.3.tgz#02341f162b6bcc1e1028e30624815d4924442dc3"
- integrity sha512-jWvmhqYpx+9EZm/FxcZSbUZyDEvDTLDi3nSAKbzEkyWvtI0mNSmUosey+5awDW1RUlrgXbQb5A6qY1xQH9U6MQ==
- dependencies:
- caniuse-lite "^1.0.30001010"
- electron-to-chromium "^1.3.306"
- node-releases "^1.1.40"
-
browserslist@^4.8.2:
version "4.8.2"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.8.2.tgz#b45720ad5fbc8713b7253c20766f701c9a694289"
@@ -3176,26 +3208,6 @@ cacache@12.0.2, cacache@^12.0.2:
unique-filename "^1.1.1"
y18n "^4.0.0"
-cacache@^11.3.2:
- version "11.3.3"
- resolved "https://registry.yarnpkg.com/cacache/-/cacache-11.3.3.tgz#8bd29df8c6a718a6ebd2d010da4d7972ae3bbadc"
- integrity sha512-p8WcneCytvzPxhDvYp31PD039vi77I12W+/KfR9S8AZbaiARFBCpsPJS+9uhWfeBfeAtW7o/4vt3MUqLkbY6nA==
- dependencies:
- bluebird "^3.5.5"
- chownr "^1.1.1"
- figgy-pudding "^3.5.1"
- glob "^7.1.4"
- graceful-fs "^4.1.15"
- lru-cache "^5.1.1"
- mississippi "^3.0.0"
- mkdirp "^0.5.1"
- move-concurrently "^1.0.1"
- promise-inflight "^1.0.1"
- rimraf "^2.6.3"
- ssri "^6.0.1"
- unique-filename "^1.1.1"
- y18n "^4.0.0"
-
cacache@^12.0.0, cacache@^12.0.3:
version "12.0.3"
resolved "https://registry.yarnpkg.com/cacache/-/cacache-12.0.3.tgz#be99abba4e1bf5df461cd5a2c1071fc432573390"
@@ -3239,11 +3251,6 @@ cachedir@1.3.0:
dependencies:
os-homedir "^1.0.1"
-call-me-maybe@^1.0.1:
- version "1.0.1"
- resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.1.tgz#26d208ea89e37b5cbde60250a15f031c16a4d66b"
- integrity sha1-JtII6onje1y95gJQoV8DHBak1ms=
-
caller-callsite@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/caller-callsite/-/caller-callsite-2.0.0.tgz#847e0fce0a223750a9a027c54b33731ad3154134"
@@ -3268,14 +3275,14 @@ callsites@^3.0.0:
resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73"
integrity sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==
-camelcase-keys@^4.0.0:
- version "4.2.0"
- resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-4.2.0.tgz#a2aa5fb1af688758259c32c141426d78923b9b77"
- integrity sha1-oqpfsa9oh1glnDLBQUJteJI7m3c=
+camelcase-keys@^6.1.1:
+ version "6.1.1"
+ resolved "https://registry.yarnpkg.com/camelcase-keys/-/camelcase-keys-6.1.1.tgz#0d24dde78cea4c7d2da7f4ea40b7995083328c8d"
+ integrity sha512-kEPCddRFChEzO0d6w61yh0WbBiSv9gBnfZWGfXRYPlGqIdIGef6HMR6pgqVSEWCYkrp8B0AtEpEXNY+Jx0xk1A==
dependencies:
- camelcase "^4.1.0"
- map-obj "^2.0.0"
- quick-lru "^1.0.0"
+ camelcase "^5.3.1"
+ map-obj "^4.0.0"
+ quick-lru "^4.0.1"
camelcase@^4.1.0:
version "4.1.0"
@@ -3287,21 +3294,31 @@ camelcase@^5.0.0, camelcase@^5.3.1:
resolved "https://registry.yarnpkg.com/camelcase/-/camelcase-5.3.1.tgz#e3c9b31569e106811df242f715725a1f4c494320"
integrity sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==
-caniuse-lite@1.0.30000989, caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000984:
+caniuse-lite@1.0.30001019:
+ version "1.0.30001019"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001019.tgz#857e3fccaad2b2feb3f1f6d8a8f62d747ea648e1"
+ integrity sha512-6ljkLtF1KM5fQ+5ZN0wuyVvvebJxgJPTmScOMaFuQN2QuOzvRJnWSKfzQskQU5IOU4Gap3zasYPIinzwUjoj/g==
+
+caniuse-lite@^1.0.30000980, caniuse-lite@^1.0.30000984:
version "1.0.30000989"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30000989.tgz#b9193e293ccf7e4426c5245134b8f2a56c0ac4b9"
integrity sha512-vrMcvSuMz16YY6GSVZ0dWDTJP8jqk3iFQ/Aq5iqblPwxSVVZI+zxDyTX0VPqtQsDnfdrBDcsmhgTEOh5R8Lbpw==
-caniuse-lite@^1.0.30001010:
- version "1.0.30001012"
- resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001012.tgz#653ec635e815b9e0fb801890923b0c2079eb34ec"
- integrity sha512-7RR4Uh04t9K1uYRWzOJmzplgEOAXbfK72oVNokCdMzA67trrhPzy93ahKk1AWHiA0c58tD2P+NHqxrA8FZ+Trg==
-
caniuse-lite@^1.0.30001015:
version "1.0.30001016"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001016.tgz#16ea48d7d6e8caf3cad3295c2d746fe38c4e7f66"
integrity sha512-yYQ2QfotceRiH4U+h1Us86WJXtVHDmy3nEKIdYPsZCYnOV5/tMgGbmoIlrMzmh2VXlproqYtVaKeGDBkMZifFA==
+caniuse-lite@^1.0.30001017:
+ version "1.0.30001020"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001020.tgz#3f04c1737500ffda78be9beb0b5c1e2070e15926"
+ integrity sha512-yWIvwA68wRHKanAVS1GjN8vajAv7MBFshullKCeq/eKpK7pJBVDgFFEqvgWTkcP2+wIDeQGYFRXECjKZnLkUjA==
+
+caniuse-lite@^1.0.30001020:
+ version "1.0.30001021"
+ resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001021.tgz#e75ed1ef6dbadd580ac7e7720bb16f07b083f254"
+ integrity sha512-wuMhT7/hwkgd8gldgp2jcrUjOU9RXJ4XxGumQeOsUr91l3WwmM68Cpa/ymCnWEDqakwFXhuDQbaKNHXBPgeE9g==
+
canonical-path@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/canonical-path/-/canonical-path-1.0.0.tgz#fcb470c23958def85081856be7a86e904f180d1d"
@@ -3416,7 +3433,7 @@ chokidar@^2.0.2, chokidar@^2.1.1:
optionalDependencies:
fsevents "^1.2.7"
-chokidar@^2.0.4, chokidar@^2.1.8:
+chokidar@^2.1.8:
version "2.1.8"
resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-2.1.8.tgz#804b3a7b6a99358c3c5c61e71d8728f041cff917"
integrity sha512-ZmZUazfOzf0Nve7duiCKD23PFSCs4JPoYyccjUFF3aQkQadqBhfzhjkwBH2mNOG9cTBwhamM37EIsIkZw3nRgg==
@@ -3435,6 +3452,21 @@ chokidar@^2.0.4, chokidar@^2.1.8:
optionalDependencies:
fsevents "^1.2.7"
+chokidar@^3.3.0:
+ version "3.3.1"
+ resolved "https://registry.yarnpkg.com/chokidar/-/chokidar-3.3.1.tgz#c84e5b3d18d9a4d77558fef466b1bf16bbeb3450"
+ integrity sha512-4QYCEWOcK3OJrxwvyyAOxFuhpvOVCYkr33LPfFNBjAD/w3sEzWsp2BUOkI4l9bHvWioAd0rc6NlHUOEaWkTeqg==
+ dependencies:
+ anymatch "~3.1.1"
+ braces "~3.0.2"
+ glob-parent "~5.1.0"
+ is-binary-path "~2.1.0"
+ is-glob "~4.0.1"
+ normalize-path "~3.0.0"
+ readdirp "~3.3.0"
+ optionalDependencies:
+ fsevents "~2.1.2"
+
chownr@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/chownr/-/chownr-1.1.2.tgz#a18f1e0b269c8a6a5d3c86eb298beb14c3dd7bf6"
@@ -3762,24 +3794,6 @@ copy-descriptor@^0.1.0:
resolved "https://registry.yarnpkg.com/copy-descriptor/-/copy-descriptor-0.1.1.tgz#676f6eb3c39997c2ee1ac3a924fd6124748f578d"
integrity sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=
-copy-webpack-plugin@5.0.3:
- version "5.0.3"
- resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.0.3.tgz#2179e3c8fd69f13afe74da338896f1f01a875b5c"
- integrity sha512-PlZRs9CUMnAVylZq+vg2Juew662jWtwOXOqH4lbQD9ZFhRG9R7tVStOgHt21CBGVq7k5yIJaz8TXDLSjV+Lj8Q==
- dependencies:
- cacache "^11.3.2"
- find-cache-dir "^2.1.0"
- glob-parent "^3.1.0"
- globby "^7.1.1"
- is-glob "^4.0.1"
- loader-utils "^1.2.3"
- minimatch "^3.0.4"
- normalize-path "^3.0.0"
- p-limit "^2.2.0"
- schema-utils "^1.0.0"
- serialize-javascript "^1.7.0"
- webpack-log "^2.0.0"
-
copy-webpack-plugin@5.1.1:
version "5.1.1"
resolved "https://registry.yarnpkg.com/copy-webpack-plugin/-/copy-webpack-plugin-5.1.1.tgz#5481a03dea1123d88a988c6ff8b78247214f0b88"
@@ -3819,11 +3833,6 @@ core-js@3.2.1:
resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.2.1.tgz#cd41f38534da6cc59f7db050fe67307de9868b09"
integrity sha512-Qa5XSVefSVPRxy2XfUC13WbvqkxhkwB3ve+pgCQveNgYzbM/UxZeu1dcOX/xr4UmfUd+muuvsaxilQzCyUurMw==
-core-js@3.6.0:
- version "3.6.0"
- resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.6.0.tgz#2b854e451de1967d1e29896025cdc13a2518d9ea"
- integrity sha512-AHPTNKzyB+YwgDWoSOCaid9PUSEF6781vsfiK8qUz62zRR448/XgK2NtCbpiUGizbep8Lrpt0Du19PpGGZvw3Q==
-
core-js@^2.4.0:
version "2.6.9"
resolved "https://registry.yarnpkg.com/core-js/-/core-js-2.6.9.tgz#6b4b214620c834152e179323727fc19741b084f2"
@@ -3976,22 +3985,15 @@ cssstyle@^1.0.0, cssstyle@^1.1.1:
dependencies:
cssom "0.3.x"
-currently-unhandled@^0.4.1:
- version "0.4.1"
- resolved "https://registry.yarnpkg.com/currently-unhandled/-/currently-unhandled-0.4.1.tgz#988df33feab191ef799a61369dd76c17adf957ea"
- integrity sha1-mI3zP+qxke95mmE2nddsF635V+o=
- dependencies:
- array-find-index "^1.0.1"
-
cyclist@~0.2.2:
version "0.2.2"
resolved "https://registry.yarnpkg.com/cyclist/-/cyclist-0.2.2.tgz#1b33792e11e914a2fd6d6ed6447464444e5fa640"
integrity sha1-GzN5LhHpFKL9bW7WRHRkRE5fpkA=
-cypress@3.7.0:
- version "3.7.0"
- resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.7.0.tgz#e2cd71b87b6ce0d4c72c6ea25da1005d75c1f231"
- integrity sha512-o+vfRxqAba8TduelzfZQ4WHmj2yNEjaoO2EuZ8dZ9pJpuW+WGtBGheKIp6zkoQsp8ZgFe8OoHh1i2mY8BDnMAw==
+cypress@3.8.2:
+ version "3.8.2"
+ resolved "https://registry.yarnpkg.com/cypress/-/cypress-3.8.2.tgz#58fa96e1e7dae712403b0f4e8af1efe35442ff7a"
+ integrity sha512-aTs0u3+dfEuLe0Ct0FVO5jD1ULqxbuqWUZwzBm0rxdLgLxIAOI/A9f/WkgY5Cfy1TEXe8pKC6Wal0ZpnkdGRSw==
dependencies:
"@cypress/listr-verbose-renderer" "0.4.1"
"@cypress/xvfb" "1.2.4"
@@ -4004,6 +4006,7 @@ cypress@3.7.0:
commander "2.15.1"
common-tags "1.8.0"
debug "3.2.6"
+ eventemitter2 "4.1.2"
execa "0.10.0"
executable "4.1.1"
extract-zip "1.6.7"
@@ -4090,7 +4093,7 @@ debuglog@^1.0.1:
resolved "https://registry.yarnpkg.com/debuglog/-/debuglog-1.0.1.tgz#aa24ffb9ac3df9a2351837cfb2d279360cd78492"
integrity sha1-qiT/uaw9+aI1GDfPstJ5NgzXhJI=
-decamelize-keys@^1.0.0:
+decamelize-keys@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/decamelize-keys/-/decamelize-keys-1.1.0.tgz#d171a87933252807eb3cb61dc1c1445d078df2d9"
integrity sha1-0XGoeTMlKAfrPLYdwcFEXQeN8tk=
@@ -4260,13 +4263,20 @@ diffie-hellman@^5.0.0:
miller-rabin "^4.0.0"
randombytes "^2.0.0"
-dir-glob@^2.0.0, dir-glob@^2.2.2:
+dir-glob@^2.0.0:
version "2.2.2"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4"
integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw==
dependencies:
path-type "^3.0.0"
+dir-glob@^3.0.1:
+ version "3.0.1"
+ resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
+ integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==
+ dependencies:
+ path-type "^4.0.0"
+
dns-equal@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/dns-equal/-/dns-equal-1.0.0.tgz#b39e7f1da6eb0a75ba9c17324b34753c47e0654d"
@@ -4372,11 +4382,6 @@ electron-to-chromium@^1.3.191:
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.230.tgz#2d0618cb6f724391d5fd0926dde84d6c67cbcda9"
integrity sha512-r0RljY5DZi9RX4v8mjHxJkDWnQe+nsrkGlHtrDF2uvZcvAkw+iglvlQi1794gZhwRtJoDOomMJlDHL2LfXSCZA==
-electron-to-chromium@^1.3.306:
- version "1.3.314"
- resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.314.tgz#c186a499ed2c9057bce9eb8dca294d6d5450facc"
- integrity sha512-IKDR/xCxKFhPts7h+VaSXS02Z1mznP3fli1BbXWXeN89i2gCzKraU8qLpEid8YzKcmZdZD3Mly3cn5/lY9xsBQ==
-
electron-to-chromium@^1.3.322:
version "1.3.322"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.3.322.tgz#a6f7e1c79025c2b05838e8e344f6e89eb83213a8"
@@ -4520,7 +4525,19 @@ escape-string-regexp@^1.0.2, escape-string-regexp@^1.0.5:
resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4"
integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=
-escodegen@^1.11.0, escodegen@^1.9.1:
+escodegen@^1.11.0:
+ version "1.12.1"
+ resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.12.1.tgz#08770602a74ac34c7a90ca9229e7d51e379abc76"
+ integrity sha512-Q8t2YZ+0e0pc7NRVj3B4tSQ9rim1oi4Fh46k2xhJ2qOiEwhQfdjyEQddWdj7ZFaKmU+5104vn1qrcjEPWq+bgQ==
+ dependencies:
+ esprima "^3.1.3"
+ estraverse "^4.2.0"
+ esutils "^2.0.2"
+ optionator "^0.8.1"
+ optionalDependencies:
+ source-map "~0.6.1"
+
+escodegen@^1.9.1:
version "1.12.0"
resolved "https://registry.yarnpkg.com/escodegen/-/escodegen-1.12.0.tgz#f763daf840af172bb3a2b6dd7219c0e17f7ff541"
integrity sha512-TuA+EhsanGcme5T3R0L80u4t8CpbXQjegRmf7+FPTJrtCTErXFeelblRgHQa1FofEzqYYJmJ/OqjTwREp9qgmg==
@@ -4572,6 +4589,11 @@ etag@~1.8.1:
resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887"
integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc=
+eventemitter2@4.1.2:
+ version "4.1.2"
+ resolved "https://registry.yarnpkg.com/eventemitter2/-/eventemitter2-4.1.2.tgz#0e1a8477af821a6ef3995b311bf74c23a5247f15"
+ integrity sha1-DhqEd6+CGm7zmVsxG/dMI6UkfxU=
+
eventemitter3@^3.0.0:
version "3.1.2"
resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-3.1.2.tgz#2d3d48f9c346698fce83a85d7d664e98535df6e7"
@@ -4799,17 +4821,16 @@ fast-deep-equal@^2.0.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=
-fast-glob@^2.2.6:
- version "2.2.7"
- resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d"
- integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw==
+fast-glob@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.1.1.tgz#87ee30e9e9f3eb40d6f254a7997655da753d7c82"
+ integrity sha512-nTCREpBY8w8r+boyFYAx21iL6faSsQynliPHM4Uf56SbkyohCNxpVPEH9xrF5TXKy+IsjkPUHDKiUkzBVRXn9g==
dependencies:
- "@mrmlnc/readdir-enhanced" "^2.2.1"
- "@nodelib/fs.stat" "^1.1.2"
- glob-parent "^3.1.0"
- is-glob "^4.0.0"
- merge2 "^1.2.3"
- micromatch "^3.1.10"
+ "@nodelib/fs.stat" "^2.0.2"
+ "@nodelib/fs.walk" "^1.2.3"
+ glob-parent "^5.1.0"
+ merge2 "^1.3.0"
+ micromatch "^4.0.2"
fast-json-stable-stringify@2.0.0, fast-json-stable-stringify@2.x, fast-json-stable-stringify@^2.0.0:
version "2.0.0"
@@ -4826,6 +4847,13 @@ fastparse@^1.1.1:
resolved "https://registry.yarnpkg.com/fastparse/-/fastparse-1.1.2.tgz#91728c5a5942eced8531283c79441ee4122c35a9"
integrity sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==
+fastq@^1.6.0:
+ version "1.6.0"
+ resolved "https://registry.yarnpkg.com/fastq/-/fastq-1.6.0.tgz#4ec8a38f4ac25f21492673adb7eae9cfef47d1c2"
+ integrity sha512-jmxqQ3Z/nXoeyDmWAzF9kH1aGZSis6e/SbfPmJpUnyZ0ogr6iscHQaml4wsEepEWSdtmpy+eVXmCRIMpxaXqOA==
+ dependencies:
+ reusify "^1.0.0"
+
faye-websocket@^0.10.0:
version "0.10.0"
resolved "https://registry.yarnpkg.com/faye-websocket/-/faye-websocket-0.10.0.tgz#4e492f8d04dfb6f89003507f6edbf2d501e7c6f4"
@@ -4966,7 +4994,7 @@ find-cache-dir@^2.0.0, find-cache-dir@^2.1.0:
make-dir "^2.0.0"
pkg-dir "^3.0.0"
-find-up@^2.0.0, find-up@^2.1.0:
+find-up@^2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-2.1.0.tgz#45d1b7e506c717ddd482775a2b77920a3c0c57a7"
integrity sha1-RdG35QbHF93UgndaK3eSCjwMV6c=
@@ -4980,7 +5008,7 @@ find-up@^3.0.0:
dependencies:
locate-path "^3.0.0"
-find-up@^4.0.0:
+find-up@^4.0.0, find-up@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/find-up/-/find-up-4.1.0.tgz#97afe7d6cdc0bc5928584b7c8d7b16e8a9aa5d19"
integrity sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==
@@ -5027,19 +5055,19 @@ forever-agent@~0.6.1:
resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91"
integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=
-fork-ts-checker-webpack-plugin@0.4.15:
- version "0.4.15"
- resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-0.4.15.tgz#7cd9f94f3dd58cd1fe8f953f876e72090eda3f6d"
- integrity sha512-qNYuygh2GxXehBvQZ5rI5YlQFn+7ZV6kmkyD9Sgs33dWl73NZdUOB5aCp8v0EXJn176AhPrZP8YCMT3h01fs+g==
+fork-ts-checker-webpack-plugin@^3.1.1:
+ version "3.1.1"
+ resolved "https://registry.yarnpkg.com/fork-ts-checker-webpack-plugin/-/fork-ts-checker-webpack-plugin-3.1.1.tgz#a1642c0d3e65f50c2cc1742e9c0a80f441f86b19"
+ integrity sha512-DuVkPNrM12jR41KM2e+N+styka0EgLkTnXmNcXdgOM37vtGeY+oCBK/Jx0hzSeEU6memFCtWb4htrHPMDfwwUQ==
dependencies:
babel-code-frame "^6.22.0"
chalk "^2.4.1"
- chokidar "^2.0.4"
- lodash "^4.17.11"
+ chokidar "^3.3.0"
micromatch "^3.1.10"
minimatch "^3.0.4"
- resolve "^1.5.0"
+ semver "^5.6.0"
tapable "^1.0.0"
+ worker-rpc "^0.1.0"
form-data@~2.3.2:
version "2.3.3"
@@ -5093,12 +5121,12 @@ fs-extra@6.0.0:
jsonfile "^4.0.0"
universalify "^0.1.0"
-fs-extra@^7.0.0:
- version "7.0.1"
- resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-7.0.1.tgz#4f189c44aa123b895f722804f55ea23eadc348e9"
- integrity sha512-YJDaCJZEnBmcbw13fvdAM9AwNOJwOzrE4pqMqBq5nFiEqXUqHwlK4B+3pUw6JNvfSPtX05xFHtYy/1ni01eGCw==
+fs-extra@^8.1.0:
+ version "8.1.0"
+ resolved "https://registry.yarnpkg.com/fs-extra/-/fs-extra-8.1.0.tgz#49d43c45a88cd9677668cb7be1b46efdb8d2e1c0"
+ integrity sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==
dependencies:
- graceful-fs "^4.1.2"
+ graceful-fs "^4.2.0"
jsonfile "^4.0.0"
universalify "^0.1.0"
@@ -5137,6 +5165,11 @@ fsevents@^2.0.6:
resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.0.7.tgz#382c9b443c6cbac4c57187cdda23aa3bf1ccfc2a"
integrity sha512-a7YT0SV3RB+DjYcppwVDLtn13UQnmg0SWZS7ezZD0UjnLwXmy8Zm21GMVGLaFGimIqcvyMQaOJBrop8MyOp1kQ==
+fsevents@~2.1.2:
+ version "2.1.2"
+ resolved "https://registry.yarnpkg.com/fsevents/-/fsevents-2.1.2.tgz#4c0a1fb34bc68e543b4b82a9ec392bfbda840805"
+ integrity sha512-R4wDiBwZ0KzpgOWetKDug1FZcYhqYnUYKtfZYt4mD5SBz76q0KR4Q9o7GIPamsVPGmW3EYPPJ0dOOjvx32ldZA==
+
function-bind@^1.0.2, function-bind@^1.1.1:
version "1.1.1"
resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.1.tgz#a56899d3ea3c9bab874bb9773b7c5ede92f4895d"
@@ -5207,19 +5240,17 @@ getpass@^0.1.1:
dependencies:
assert-plus "^1.0.0"
-gh-pages@2.1.1:
- version "2.1.1"
- resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-2.1.1.tgz#5be70a92f9cb70404bafabd8bb149c0e9a8c264b"
- integrity sha512-yNW2SFp9xGRP/8Sk2WXuLI/Gn92oOL4HBgudn6PsqAnuWT90Y1tozJoTfX1WdrDSW5Rb90kLVOf5mm9KJ/2fDw==
+gh-pages@2.2.0:
+ version "2.2.0"
+ resolved "https://registry.yarnpkg.com/gh-pages/-/gh-pages-2.2.0.tgz#74ebeaca8d2b9a11279dcbd4a39ddfff3e6caa24"
+ integrity sha512-c+yPkNOPMFGNisYg9r4qvsMIjVYikJv7ImFOhPIVPt0+AcRUamZ7zkGRLHz7FKB0xrlZ+ddSOJsZv9XAFVXLmA==
dependencies:
async "^2.6.1"
commander "^2.18.0"
email-addresses "^3.0.1"
filenamify-url "^1.0.0"
- fs-extra "^7.0.0"
+ fs-extra "^8.1.0"
globby "^6.1.0"
- graceful-fs "^4.1.11"
- rimraf "^2.6.2"
glob-parent@^3.1.0:
version "3.1.0"
@@ -5236,10 +5267,12 @@ glob-parent@^5.0.0:
dependencies:
is-glob "^4.0.1"
-glob-to-regexp@^0.3.0:
- version "0.3.0"
- resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab"
- integrity sha1-jFoUlNIGbFcMw7/kSWF1rMTVAqs=
+glob-parent@^5.1.0, glob-parent@~5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.0.tgz#5f4c1d1e748d30cd73ad2944b3577a81b081e8c2"
+ integrity sha512-qjtRgnIVmOfnKUE3NJAQEdk+lKrxfw8t5ke7SXtfMTHcjsBfOfWXCQfdb30zfDoZQ2IRSIiidmjtbHZPZ++Ihw==
+ dependencies:
+ is-glob "^4.0.1"
glob@7.0.x:
version "7.0.6"
@@ -5298,6 +5331,18 @@ globals@^9.18.0:
resolved "https://registry.yarnpkg.com/globals/-/globals-9.18.0.tgz#aa3896b3e69b487f17e31ed2143d69a8e30c2d8a"
integrity sha512-S0nG3CLEQiY/ILxqtztTWH/3iRRdyBLw6KMDxnKMchrtbj2OFmehVh0WUCfW3DUrIgx/qFrJPICrq4Z4sTR9UQ==
+globby@^11.0.0:
+ version "11.0.0"
+ resolved "https://registry.yarnpkg.com/globby/-/globby-11.0.0.tgz#56fd0e9f0d4f8fb0c456f1ab0dee96e1380bc154"
+ integrity sha512-iuehFnR3xu5wBBtm4xi0dMe92Ob87ufyu/dHwpDYfbcpYpIbrO5OnS8M1vWvrBhSGEJ3/Ecj7gnX76P8YxpPEg==
+ dependencies:
+ array-union "^2.1.0"
+ dir-glob "^3.0.1"
+ fast-glob "^3.1.1"
+ ignore "^5.1.4"
+ merge2 "^1.3.0"
+ slash "^3.0.0"
+
globby@^6.1.0:
version "6.1.0"
resolved "https://registry.yarnpkg.com/globby/-/globby-6.1.0.tgz#f5a6d70e8395e21c858fb0489d64df02424d506c"
@@ -5321,20 +5366,6 @@ globby@^7.1.1:
pify "^3.0.0"
slash "^1.0.0"
-globby@^9.2.0:
- version "9.2.0"
- resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d"
- integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg==
- dependencies:
- "@types/glob" "^7.1.1"
- array-union "^1.0.2"
- dir-glob "^2.2.2"
- fast-glob "^2.2.6"
- glob "^7.1.3"
- ignore "^4.0.3"
- pify "^4.0.1"
- slash "^2.0.0"
-
globjoin@^0.1.4:
version "0.1.4"
resolved "https://registry.yarnpkg.com/globjoin/-/globjoin-0.1.4.tgz#2f4494ac8919e3767c5cbb691e9f463324285d43"
@@ -5352,6 +5383,11 @@ graceful-fs@^4.1.11, graceful-fs@^4.1.15, graceful-fs@^4.1.2, graceful-fs@^4.1.6
resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.2.tgz#6f0952605d0140c1cfdb138ed005775b92d67b02"
integrity sha512-IItsdsea19BoLC7ELy13q1iJFNmd7ofZH5+X/pJr90/nRoPEX0DJo1dHDbgtYWOhJhcCgMDTOw84RZ72q6lB+Q==
+graceful-fs@^4.2.0:
+ version "4.2.3"
+ resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.3.tgz#4a12ff1b60376ef09862c2093edd908328be8423"
+ integrity sha512-a30VEBm4PEdx1dRB7MFK7BejejvCvBronbLjht+sHuGYj8PHs7M/5Z+rt5lw551vZ7yfTCj4Vuyy3mSJytDWRQ==
+
growly@^1.3.0:
version "1.3.0"
resolved "https://registry.yarnpkg.com/growly/-/growly-1.3.0.tgz#f10748cbe76af964b7c96c93c6bcc28af120c081"
@@ -5367,6 +5403,17 @@ handle-thing@^2.0.0:
resolved "https://registry.yarnpkg.com/handle-thing/-/handle-thing-2.0.0.tgz#0e039695ff50c93fc288557d696f3c1dc6776754"
integrity sha512-d4sze1JNC454Wdo2fkuyzCr6aHcbL6PGGuFAz0Li/NcOm1tCHGnWDRmJP85dh9IhQErTc2svWFEX5xHIOo//kQ==
+handlebars@4.7.2:
+ version "4.7.2"
+ resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.2.tgz#01127b3840156a0927058779482031afe0e730d7"
+ integrity sha512-4PwqDL2laXtTWZghzzCtunQUTLbo31pcCJrd/B/9JP8XbhVzpS5ZXuKqlOzsd1rtcaLo4KqAn8nl8mkknS4MHw==
+ dependencies:
+ neo-async "^2.6.0"
+ optimist "^0.6.1"
+ source-map "^0.6.1"
+ optionalDependencies:
+ uglify-js "^3.1.4"
+
handlebars@^4.1.2:
version "4.1.2"
resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.1.2.tgz#b6b37c1ced0306b221e094fc7aca3ec23b131b67"
@@ -5391,6 +5438,11 @@ har-validator@~5.1.0:
ajv "^6.5.5"
har-schema "^2.0.0"
+hard-rejection@^2.0.0:
+ version "2.1.0"
+ resolved "https://registry.yarnpkg.com/hard-rejection/-/hard-rejection-2.1.0.tgz#1c6eda5c1685c63942766d79bb40ae773cecd883"
+ integrity sha512-VIZB+ibDhx7ObhAe7OVtoEbuP4h/MuOTHJ+J8h/eBXotJYl0fBgR72xDFCKgIh22OJZIOVNxBMWuhAr10r8HdA==
+
has-ansi@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/has-ansi/-/has-ansi-2.0.0.tgz#34f5049ce1ecdf2b0649af3ef24e45ed35416d91"
@@ -5472,6 +5524,14 @@ hash.js@^1.0.0, hash.js@^1.0.3:
inherits "^2.0.3"
minimalistic-assert "^1.0.1"
+hasha@5.1.0:
+ version "5.1.0"
+ resolved "https://registry.yarnpkg.com/hasha/-/hasha-5.1.0.tgz#dd05ccdfcfe7dab626247ce2a58efe461922f4ca"
+ integrity sha512-OFPDWmzPN1l7atOV1TgBVmNtBxaIysToK6Ve9DK+vT6pYuklw/nPNT+HJbZi0KDcI6vWB+9tgvZ5YD7fA3CXcA==
+ dependencies:
+ is-stream "^2.0.0"
+ type-fest "^0.8.0"
+
hmac-drbg@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/hmac-drbg/-/hmac-drbg-1.0.1.tgz#d2745701025a6c775a6c545793ed502fc0c649a1"
@@ -5670,11 +5730,6 @@ ignore@^3.3.5:
resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043"
integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug==
-ignore@^4.0.3:
- version "4.0.6"
- resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc"
- integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==
-
ignore@^5.1.4:
version "5.1.4"
resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.1.4.tgz#84b7b3dbe64552b6ef0eca99f6743dbec6d97adf"
@@ -5745,6 +5800,11 @@ indent-string@^3.0.0:
resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-3.2.0.tgz#4a5fd6d27cc332f37e5419a504dbb837105c9289"
integrity sha1-Sl/W0nzDMvN+VBmlBNu4NxBckok=
+indent-string@^4.0.0:
+ version "4.0.0"
+ resolved "https://registry.yarnpkg.com/indent-string/-/indent-string-4.0.0.tgz#624f8f4497d619b2d9768531d58f4122854d7251"
+ integrity sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==
+
indexes-of@^1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/indexes-of/-/indexes-of-1.0.1.tgz#f30f716c8e2bd346c7b67d3df3915566a7c05607"
@@ -5896,7 +5956,7 @@ is-binary-path@^1.0.0:
dependencies:
binary-extensions "^1.0.0"
-is-binary-path@^2.1.0:
+is-binary-path@^2.1.0, is-binary-path@~2.1.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/is-binary-path/-/is-binary-path-2.1.0.tgz#ea1f7f3b80f064236e83470f86c09c254fb45b09"
integrity sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==
@@ -6032,7 +6092,7 @@ is-glob@^3.1.0:
dependencies:
is-extglob "^2.1.0"
-is-glob@^4.0.0, is-glob@^4.0.1:
+is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.1.tgz#7567dbe9f2f5e2467bc77ab83c4a29482407a5dc"
integrity sha512-5G0tKtBTFImOqDnLB2hG6Bp2qcKEFduo4tZu9MT/H6NQv/ghhy30o55ufafxJ/LdH79LLs2Kfrn85TLKyA7BUg==
@@ -6129,6 +6189,11 @@ is-stream@^1.1.0:
resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-1.1.0.tgz#12d4a3dd4e68e0b79ceb8dbc84173ae80d91ca44"
integrity sha1-EtSj3U5o4Lec6428hBc66A2RykQ=
+is-stream@^2.0.0:
+ version "2.0.0"
+ resolved "https://registry.yarnpkg.com/is-stream/-/is-stream-2.0.0.tgz#bde9c32680d6fae04129d6ac9d921ce7815f78e3"
+ integrity sha512-XCoy+WlUr7d1+Z8GgSuXmpuUFC9fOhRXglJMx+dwLKTkL44Cjd4W1Z5P+BQZpr+cR93aGP4S/s7Ftw6Nd/kiEw==
+
is-symbol@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-symbol/-/is-symbol-1.0.2.tgz#a055f6ae57192caee329e7a860118b497a950f38"
@@ -7141,14 +7206,6 @@ loose-envify@^1.0.0:
dependencies:
js-tokens "^3.0.0 || ^4.0.0"
-loud-rejection@^1.0.0:
- version "1.6.0"
- resolved "https://registry.yarnpkg.com/loud-rejection/-/loud-rejection-1.6.0.tgz#5b46f80147edee578870f086d04821cf998e551f"
- integrity sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=
- dependencies:
- currently-unhandled "^0.4.1"
- signal-exit "^3.0.0"
-
lru-cache@^4.0.1:
version "4.1.5"
resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd"
@@ -7237,10 +7294,10 @@ map-obj@^1.0.0:
resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d"
integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=
-map-obj@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-2.0.0.tgz#a65cd29087a92598b8791257a523e021222ac1f9"
- integrity sha1-plzSkIepJZi4eRJXpSPgISIqwfk=
+map-obj@^4.0.0:
+ version "4.1.0"
+ resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-4.1.0.tgz#b91221b542734b9f14256c0132c897c5d7256fd5"
+ integrity sha512-glc9y00wgtwcDmp7GaE/0b0OnxpNJsVf3ael/An6Fe2Q51LLwN1er6sdomLRzz5h0+yMpiYLhWYF5R7HeqVd4g==
map-visit@^1.0.0:
version "1.0.0"
@@ -7314,20 +7371,22 @@ memorystream@^0.3.1:
resolved "https://registry.yarnpkg.com/memorystream/-/memorystream-0.3.1.tgz#86d7090b30ce455d63fbae12dda51a47ddcaf9b2"
integrity sha1-htcJCzDORV1j+64S3aUaR93K+bI=
-meow@^5.0.0:
- version "5.0.0"
- resolved "https://registry.yarnpkg.com/meow/-/meow-5.0.0.tgz#dfc73d63a9afc714a5e371760eb5c88b91078aa4"
- integrity sha512-CbTqYU17ABaLefO8vCU153ZZlprKYWDljcndKKDCFcYQITzWCXZAVk4QMFZPgvzrnUQ3uItnIE/LoUOwrT15Ig==
- dependencies:
- camelcase-keys "^4.0.0"
- decamelize-keys "^1.0.0"
- loud-rejection "^1.0.0"
- minimist-options "^3.0.1"
- normalize-package-data "^2.3.4"
- read-pkg-up "^3.0.0"
- redent "^2.0.0"
- trim-newlines "^2.0.0"
- yargs-parser "^10.0.0"
+meow@^6.0.0:
+ version "6.0.0"
+ resolved "https://registry.yarnpkg.com/meow/-/meow-6.0.0.tgz#949196fdf21d979379e3bdccb0411e60f8cffd93"
+ integrity sha512-x4rYsjigPBDAxY+BGuK83YLhUIqui5wYyZoqb6QJCUOs+0fiYq+i/NV4Jt8OgIfObZFxG9iTyvLDu4UTohGTFw==
+ dependencies:
+ "@types/minimist" "^1.2.0"
+ camelcase-keys "^6.1.1"
+ decamelize-keys "^1.1.0"
+ hard-rejection "^2.0.0"
+ minimist-options "^4.0.1"
+ normalize-package-data "^2.5.0"
+ read-pkg-up "^7.0.0"
+ redent "^3.0.0"
+ trim-newlines "^3.0.0"
+ type-fest "^0.8.1"
+ yargs-parser "^16.1.0"
merge-descriptors@1.0.1:
version "1.0.1"
@@ -7339,16 +7398,21 @@ merge-stream@^2.0.0:
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==
-merge2@^1.2.3:
- version "1.2.4"
- resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.2.4.tgz#c9269589e6885a60cf80605d9522d4b67ca646e3"
- integrity sha512-FYE8xI+6pjFOhokZu0We3S5NKCirLbCzSh2Usf3qEyr4X8U+0jNg9P8RZ4qz+V2UoECLVwSyzU3LxXBaLGtD3A==
+merge2@^1.3.0:
+ version "1.3.0"
+ resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.3.0.tgz#5b366ee83b2f1582c48f87e47cf1a9352103ca81"
+ integrity sha512-2j4DAdlBOkiSZIsaXk4mTE3sRS02yBHAtfy127xRV3bQUFqXkjHCHLW6Scv7DwNRbIWNHH8zpnz9zMaKXIdvYw==
methods@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee"
integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4=
+microevent.ts@~0.1.1:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/microevent.ts/-/microevent.ts-0.1.1.tgz#70b09b83f43df5172d0205a63025bce0f7357fa0"
+ integrity sha512-jo1OfR4TaEwd5HOrt5+tAZ9mqT4jmpNAusXtyfNzqVm9uiSYFZlKM1wYL4oU7azZW/PxQW53wM0S6OR1JHNa2g==
+
micromatch@^3.1.10, micromatch@^3.1.4:
version "3.1.10"
resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23"
@@ -7416,6 +7480,11 @@ mimic-fn@^2.0.0, mimic-fn@^2.1.0:
resolved "https://registry.yarnpkg.com/mimic-fn/-/mimic-fn-2.1.0.tgz#7ed2c2ccccaf84d3ffcb7a69b57711fc2083401b"
integrity sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==
+min-indent@^1.0.0:
+ version "1.0.0"
+ resolved "https://registry.yarnpkg.com/min-indent/-/min-indent-1.0.0.tgz#cfc45c37e9ec0d8f0a0ec3dd4ef7f7c3abe39256"
+ integrity sha1-z8RcN+nsDY8KDsPdTvf3w6vjklY=
+
mini-css-extract-plugin@0.8.0:
version "0.8.0"
resolved "https://registry.yarnpkg.com/mini-css-extract-plugin/-/mini-css-extract-plugin-0.8.0.tgz#81d41ec4fe58c713a96ad7c723cdb2d0bd4d70e1"
@@ -7443,10 +7512,10 @@ minimatch@3.0.4, minimatch@^3.0.2, minimatch@^3.0.4:
dependencies:
brace-expansion "^1.1.7"
-minimist-options@^3.0.1:
- version "3.0.2"
- resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-3.0.2.tgz#fba4c8191339e13ecf4d61beb03f070103f3d954"
- integrity sha512-FyBrT/d0d4+uiZRbqznPXqw3IpZZG3gl3wKWiX784FycUKVwBt0uLBFkQrtE4tZOrgo78nZp2jnKz3L65T5LdQ==
+minimist-options@^4.0.1:
+ version "4.0.2"
+ resolved "https://registry.yarnpkg.com/minimist-options/-/minimist-options-4.0.2.tgz#29c4021373ded40d546186725e57761e4b1984a7"
+ integrity sha512-seq4hpWkYSUh1y7NXxzucwAN9yVlBc3Upgdjz8vLCP97jG8kaOmzYrVH/m7tQ1NYD1wdtZbSLfdy4zFmRWuc/w==
dependencies:
arrify "^1.0.1"
is-plain-obj "^1.1.0"
@@ -7712,13 +7781,6 @@ node-releases@^1.1.25:
dependencies:
semver "^5.3.0"
-node-releases@^1.1.40:
- version "1.1.41"
- resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.41.tgz#57674a82a37f812d18e3b26118aefaf53a00afed"
- integrity sha512-+IctMa7wIs8Cfsa8iYzeaLTFwv5Y4r5jZud+4AnfymzeEXKBCavFX0KBgzVaPVqf0ywa6PrO8/b+bPqdwjGBSg==
- dependencies:
- semver "^6.3.0"
-
node-releases@^1.1.42:
version "1.1.43"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.43.tgz#2c6ca237f88ce11d49631f11190bb01f8d0549f2"
@@ -7726,6 +7788,13 @@ node-releases@^1.1.42:
dependencies:
semver "^6.3.0"
+node-releases@^1.1.44:
+ version "1.1.45"
+ resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-1.1.45.tgz#4cf7e9175d71b1317f15ffd68ce63bce1d53e9f2"
+ integrity sha512-cXvGSfhITKI8qsV116u2FTzH5EWZJfgG7d4cpqwF8I8+1tWpD6AsvvGRKq2onR0DNj1jfqsjkXZsm14JMS7Cyg==
+ dependencies:
+ semver "^6.3.0"
+
nopt@^4.0.1:
version "4.0.1"
resolved "https://registry.yarnpkg.com/nopt/-/nopt-4.0.1.tgz#d0d4685afd5415193c8c7505602d0d17cd64474d"
@@ -7734,7 +7803,7 @@ nopt@^4.0.1:
abbrev "1"
osenv "^0.1.4"
-normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.3.4, normalize-package-data@^2.4.0:
+normalize-package-data@^2.0.0, normalize-package-data@^2.3.2, normalize-package-data@^2.4.0, normalize-package-data@^2.5.0:
version "2.5.0"
resolved "https://registry.yarnpkg.com/normalize-package-data/-/normalize-package-data-2.5.0.tgz#e66db1838b200c1dfc233225d12cb36520e234a8"
integrity sha512-/5CMN3T0R4XTj4DcGaexo+roZSdSFW/0AOOTROrjxzCG1wrWXEsGbRKevjlIL+ZDE4sZlJr5ED4YW0yqmkK+eA==
@@ -7751,7 +7820,7 @@ normalize-path@^2.1.1:
dependencies:
remove-trailing-separator "^1.0.1"
-normalize-path@^3.0.0:
+normalize-path@^3.0.0, normalize-path@~3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65"
integrity sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==
@@ -8366,6 +8435,11 @@ picomatch@^2.0.4, picomatch@^2.0.5:
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.0.7.tgz#514169d8c7cd0bdbeecc8a2609e34a7163de69f6"
integrity sha512-oLHIdio3tZ0qH76NybpeneBhYVj0QFTfXEFTc/B3zKQspYfYYkWYgFsmzo+4kvId/bQRcNkVeguI3y+CD22BtA==
+picomatch@^2.0.7:
+ version "2.2.1"
+ resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.2.1.tgz#21bac888b6ed8601f831ce7816e335bc779f0a4a"
+ integrity sha512-ISBaA8xQNmwELC7eOjqFKMESB2VIqt4PPDD0nsS95b/9dZXvVKOlz9keMSnoGGKcOHXfTvDD6WMaRoSc9UuhRA==
+
pidtree@^0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/pidtree/-/pidtree-0.3.0.tgz#f6fada10fccc9f99bf50e90d0b23d72c9ebc2e6b"
@@ -8584,7 +8658,7 @@ postcss@7.0.17, postcss@^7.0.0, postcss@^7.0.1, postcss@^7.0.14, postcss@^7.0.17
source-map "^0.6.1"
supports-color "^6.1.0"
-postcss@^7.0.21, postcss@^7.0.23:
+postcss@^7.0.21:
version "7.0.23"
resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.23.tgz#9f9759fad661b15964f3cfc3140f66f1e05eadc1"
integrity sha512-hOlMf3ouRIFXD+j2VJecwssTwbvsPGJVMzupptg+85WA+i7MwyrydmQAgY3R+m0Bc0exunhbJmijy8u8+vufuQ==
@@ -8593,6 +8667,15 @@ postcss@^7.0.21, postcss@^7.0.23:
source-map "^0.6.1"
supports-color "^6.1.0"
+postcss@^7.0.26:
+ version "7.0.26"
+ resolved "https://registry.yarnpkg.com/postcss/-/postcss-7.0.26.tgz#5ed615cfcab35ba9bbb82414a4fa88ea10429587"
+ integrity sha512-IY4oRjpXWYshuTDFxMVkJDtWIk2LhsTlu8bZnbEJA4+bYT16Lvpo8Qv6EvDumhYRgzjZl489pmsY3qVgJQ08nA==
+ dependencies:
+ chalk "^2.4.2"
+ source-map "^0.6.1"
+ supports-color "^6.1.0"
+
prelude-ls@~1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/prelude-ls/-/prelude-ls-1.1.2.tgz#21932a549f5e52ffd9a827f570e04be62a97da54"
@@ -8603,11 +8686,6 @@ prepend-http@^1.0.0:
resolved "https://registry.yarnpkg.com/prepend-http/-/prepend-http-1.0.4.tgz#d4f4562b0ce3696e41ac52d0e002e57a635dc6dc"
integrity sha1-1PRWKwzjaW5BrFLQ4ALlemNdxtw=
-prettier@1.18.2:
- version "1.18.2"
- resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.18.2.tgz#6823e7c5900017b4bd3acf46fe9ac4b4d7bda9ea"
- integrity sha512-OeHeMc0JhFE9idD4ZdtNibzY0+TPHSpSSb9h8FqtP+YnoZZ1sl8Vc9b1sasjfymH3SonAF4QcA2+mzHPhMvIiw==
-
prettier@1.19.1:
version "1.19.1"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-1.19.1.tgz#f7d7f5ff8a9cd872a7be4ca142095956a60797cb"
@@ -8781,10 +8859,10 @@ querystringify@^2.1.1:
resolved "https://registry.yarnpkg.com/querystringify/-/querystringify-2.1.1.tgz#60e5a5fd64a7f8bfa4d2ab2ed6fdf4c85bad154e"
integrity sha512-w7fLxIRCRT7U8Qu53jQnJyPkYZIaR4n5151KMfcJlO/A9397Wxb1amJvROTK6TOnp7PfoAmg/qXiNHI+08jRfA==
-quick-lru@^1.0.0:
- version "1.1.0"
- resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-1.1.0.tgz#4360b17c61136ad38078397ff11416e186dcfbb8"
- integrity sha1-Q2CxfGETatOAeDl/8RQW4Ybc+7g=
+quick-lru@^4.0.1:
+ version "4.0.1"
+ resolved "https://registry.yarnpkg.com/quick-lru/-/quick-lru-4.0.1.tgz#5b8878f113a58217848c6482026c73e1ba57727f"
+ integrity sha512-ARhCpm70fzdcvNQfPoy49IaanKkTlRWF2JMzqhcJbhSFRZv7nPTvZJdcY7301IPmvW+/p0RgIWnQDLJxifsQ7g==
ramda@0.24.1:
version "0.24.1"
@@ -8872,14 +8950,6 @@ read-package-tree@5.3.1:
readdir-scoped-modules "^1.0.0"
util-promisify "^2.1.0"
-read-pkg-up@^3.0.0:
- version "3.0.0"
- resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-3.0.0.tgz#3ed496685dba0f8fe118d0691dc51f4a1ff96f07"
- integrity sha1-PtSWaF26D4/hGNBpHcUfSh/5bwc=
- dependencies:
- find-up "^2.0.0"
- read-pkg "^3.0.0"
-
read-pkg-up@^4.0.0:
version "4.0.0"
resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-4.0.0.tgz#1b221c6088ba7799601c808f91161c66e58f8978"
@@ -8888,6 +8958,15 @@ read-pkg-up@^4.0.0:
find-up "^3.0.0"
read-pkg "^3.0.0"
+read-pkg-up@^7.0.0:
+ version "7.0.1"
+ resolved "https://registry.yarnpkg.com/read-pkg-up/-/read-pkg-up-7.0.1.tgz#f3a6135758459733ae2b95638056e1854e7ef507"
+ integrity sha512-zK0TB7Xd6JpCLmlLmufqykGE+/TlOePD6qKClNW7hHDKFh/J7/7gCWGR7joEQEW1bKq3a3yUZSObOoWLFQ4ohg==
+ dependencies:
+ find-up "^4.1.0"
+ read-pkg "^5.2.0"
+ type-fest "^0.8.1"
+
read-pkg@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-3.0.0.tgz#9cbc686978fee65d16c00e2b19c237fcf6e38389"
@@ -8897,6 +8976,16 @@ read-pkg@^3.0.0:
normalize-package-data "^2.3.2"
path-type "^3.0.0"
+read-pkg@^5.2.0:
+ version "5.2.0"
+ resolved "https://registry.yarnpkg.com/read-pkg/-/read-pkg-5.2.0.tgz#7bf295438ca5a33e56cd30e053b34ee7250c93cc"
+ integrity sha512-Ug69mNOpfvKDAc2Q8DRpMjjzdtrnv9HcSMX+4VsZxD1aZ6ZzrIE7rlzXBtWTyhULSMKg076AW6WR5iZpD0JiOg==
+ dependencies:
+ "@types/normalize-package-data" "^2.4.0"
+ normalize-package-data "^2.5.0"
+ parse-json "^5.0.0"
+ type-fest "^0.6.0"
+
"readable-stream@1 || 2", readable-stream@^2.0.0, readable-stream@^2.0.1, readable-stream@^2.0.2, readable-stream@^2.0.6, readable-stream@^2.1.5, readable-stream@^2.2.2, readable-stream@^2.3.3, readable-stream@^2.3.6, readable-stream@~2.3.6:
version "2.3.6"
resolved "https://registry.yarnpkg.com/readable-stream/-/readable-stream-2.3.6.tgz#b11c27d88b8ff1fbe070643cf94b0c79ae1b0aaf"
@@ -8945,6 +9034,13 @@ readdirp@^3.1.1:
dependencies:
picomatch "^2.0.4"
+readdirp@~3.3.0:
+ version "3.3.0"
+ resolved "https://registry.yarnpkg.com/readdirp/-/readdirp-3.3.0.tgz#984458d13a1e42e2e9f5841b129e162f369aff17"
+ integrity sha512-zz0pAkSPOXXm1viEwygWIPSPkcBYjW1xU5j/JBh5t9bGCJwa6f9+BJa6VaB2g+b55yVrmXzqkyLf4xaWYM0IkQ==
+ dependencies:
+ picomatch "^2.0.7"
+
realpath-native@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/realpath-native/-/realpath-native-1.1.0.tgz#2003294fea23fb0672f2476ebe22fcf498a2d65c"
@@ -8952,13 +9048,13 @@ realpath-native@^1.1.0:
dependencies:
util.promisify "^1.0.0"
-redent@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/redent/-/redent-2.0.0.tgz#c1b2007b42d57eb1389079b3c8333639d5e1ccaa"
- integrity sha1-wbIAe0LVfrE4kHmzyDM2OdXhzKo=
+redent@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/redent/-/redent-3.0.0.tgz#e557b7998316bb53c9f1f56fa626352c6963059f"
+ integrity sha512-6tDA8g98We0zd0GvVeMT9arEOnTw9qM03L9cJXaCjrip1OO764RDBLBfrB4cwzNGDj5OA5ioymC9GkizgWJDUg==
dependencies:
- indent-string "^3.0.0"
- strip-indent "^2.0.0"
+ indent-string "^4.0.0"
+ strip-indent "^3.0.0"
reflect-metadata@^0.1.2:
version "0.1.13"
@@ -9247,7 +9343,7 @@ resolve@1.1.7:
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.1.7.tgz#203114d82ad2c5ed9e8e0411b3932875e889e97b"
integrity sha1-IDEU2CrSxe2ejgQRs5ModeiJ6Xs=
-resolve@1.x, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2, resolve@^1.5.0:
+resolve@1.x, resolve@^1.1.7, resolve@^1.10.0, resolve@^1.3.2:
version "1.12.0"
resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.12.0.tgz#3fc644a35c84a48554609ff26ec52b66fa577df6"
integrity sha512-B/dOmuoAik5bKcD6s6nXDCjzUKnaDvdkRyAk6rsmsKLipWj4797iothd7jmmUhWTfinVMU+wc56rYKsit2Qy4w==
@@ -9285,6 +9381,11 @@ retry@^0.12.0:
resolved "https://registry.yarnpkg.com/retry/-/retry-0.12.0.tgz#1b42a6266a21f07421d1b0b54b7dc167b01c013b"
integrity sha1-G0KmJmoh8HQh0bC1S33BZ7AcATs=
+reusify@^1.0.0:
+ version "1.0.4"
+ resolved "https://registry.yarnpkg.com/reusify/-/reusify-1.0.4.tgz#90da382b1e126efc02146e90845a88db12925d76"
+ integrity sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==
+
rimraf@2.6.3:
version "2.6.3"
resolved "https://registry.yarnpkg.com/rimraf/-/rimraf-2.6.3.tgz#b2d104fe0d8fb27cf9e0a1cda8262dd3833c6cab"
@@ -9326,6 +9427,11 @@ run-async@^2.2.0:
dependencies:
is-promise "^2.1.0"
+run-parallel@^1.1.9:
+ version "1.1.9"
+ resolved "https://registry.yarnpkg.com/run-parallel/-/run-parallel-1.1.9.tgz#c9dd3a7cf9f4b2c4b6244e173a6ed866e61dd679"
+ integrity sha512-DEqnSRTDw/Tc3FXf49zedI638Z9onwUotBMiUFKmrO2sdFKIbXamXGQ3Axd4qgphxKB4kw/qP1w5kTxnfU1B9Q==
+
run-queue@^1.0.0, run-queue@^1.0.3:
version "1.0.3"
resolved "https://registry.yarnpkg.com/run-queue/-/run-queue-1.0.3.tgz#e848396f057d223f24386924618e25694161ec47"
@@ -9340,10 +9446,10 @@ rxjs@6.4.0:
dependencies:
tslib "^1.9.0"
-rxjs@6.5.3:
- version "6.5.3"
- resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.3.tgz#510e26317f4db91a7eb1de77d9dd9ba0a4899a3a"
- integrity sha512-wuYsAYYFdWTAnAaPoKGNhfpWwKZbJW+HgAJ+mImp+Epl7BG8oNWBCTyRM8gba9k4lk8BgWdoYm21Mo/RYhhbgA==
+rxjs@6.5.4:
+ version "6.5.4"
+ resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.5.4.tgz#e0777fe0d184cec7872df147f303572d414e211c"
+ integrity sha512-naMQXcgEo3csAEGvw/NydRA0fuS2nDZJiw1YUWFKU7aPPAPGZEsD4Iimit96qwCieH6y614MCLYwdkrWx7z/7Q==
dependencies:
tslib "^1.9.0"
@@ -10116,10 +10222,12 @@ strip-eof@^1.0.0:
resolved "https://registry.yarnpkg.com/strip-eof/-/strip-eof-1.0.0.tgz#bb43ff5598a6eb05d89b59fcd129c983313606bf"
integrity sha1-u0P/VZim6wXYm1n80SnJgzE2Br8=
-strip-indent@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-2.0.0.tgz#5ef8db295d01e6ed6cbf7aab96998d7822527b68"
- integrity sha1-XvjbKV0B5u1sv3qrlpmNeCJSe2g=
+strip-indent@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/strip-indent/-/strip-indent-3.0.0.tgz#c32e1cee940b6b3432c771bc2c54bcce73cd3001"
+ integrity sha512-laJTa3Jb+VQpaC6DseHhF7dXVqHTfJPCRDaEbid/drOhgitgYku/letMUqOXFoWV0zIIUbjpdH2t+tYj4bQMRQ==
+ dependencies:
+ min-indent "^1.0.0"
strip-json-comments@2.0.1, strip-json-comments@~2.0.1:
version "2.0.1"
@@ -10183,12 +10291,12 @@ stylelint-scss@3.13.0:
postcss-selector-parser "^6.0.2"
postcss-value-parser "^4.0.2"
-stylelint@12.0.0:
- version "12.0.0"
- resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-12.0.0.tgz#2e8613675f7be11769ce474f45137fdf7751380a"
- integrity sha512-TwqtATrFOT07SPlUGyHN7tVhWqxwitn5BlAvyBQy/ekA+Nwu4mLU9L1dvGQPNxHUBLowjvkSW18QzHHR6/FVVQ==
+stylelint@13.0.0:
+ version "13.0.0"
+ resolved "https://registry.yarnpkg.com/stylelint/-/stylelint-13.0.0.tgz#532007f7154c1a5ed14245d857a5884316f5111f"
+ integrity sha512-6sjgOJbM3iLhnUtmRO0J1vvxie9VnhIZX/2fCehjylv9Gl9u0ytehGCTm9Lhw2p1F8yaNZn5UprvhCB8C3g/Tg==
dependencies:
- autoprefixer "^9.7.1"
+ autoprefixer "^9.7.3"
balanced-match "^1.0.0"
chalk "^3.0.0"
cosmiconfig "^6.0.0"
@@ -10197,7 +10305,7 @@ stylelint@12.0.0:
file-entry-cache "^5.0.1"
get-stdin "^7.0.0"
global-modules "^2.0.0"
- globby "^9.2.0"
+ globby "^11.0.0"
globjoin "^0.1.4"
html-tags "^3.1.0"
ignore "^5.1.4"
@@ -10208,10 +10316,10 @@ stylelint@12.0.0:
lodash "^4.17.15"
log-symbols "^3.0.0"
mathml-tag-names "^2.1.1"
- meow "^5.0.0"
+ meow "^6.0.0"
micromatch "^4.0.2"
normalize-selector "^0.2.0"
- postcss "^7.0.21"
+ postcss "^7.0.26"
postcss-html "^0.36.0"
postcss-jsx "^0.36.3"
postcss-less "^3.1.4"
@@ -10531,10 +10639,10 @@ tree-kill@1.2.1:
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.1.tgz#5398f374e2f292b9dcc7b2e71e30a5c3bb6c743a"
integrity sha512-4hjqbObwlh2dLyW4tcz0Ymw0ggoaVDMveUB9w8kFSQScdRLo0gxO9J7WFcUBo+W3C1TLdFIEwNOWebgZZ0RH9Q==
-trim-newlines@^2.0.0:
- version "2.0.0"
- resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-2.0.0.tgz#b403d0b91be50c331dfc4b82eeceb22c3de16d20"
- integrity sha1-tAPQuRvlDDMd/EuC7s6yLD3hbSA=
+trim-newlines@^3.0.0:
+ version "3.0.0"
+ resolved "https://registry.yarnpkg.com/trim-newlines/-/trim-newlines-3.0.0.tgz#79726304a6a898aa8373427298d54c2ee8b1cb30"
+ integrity sha512-C4+gOpvmxaSMKuEf9Qc134F1ZuOHVXKRbtEflf4NTtuuJDEIJ9p5PXsalL8SkeRw+qit1Mo+yuvMPAKwWg/1hA==
trim-repeated@^1.0.0:
version "1.0.0"
@@ -10563,10 +10671,10 @@ trough@^1.0.0:
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.4.tgz#3b52b1f13924f460c3fbfd0df69b587dbcbc762e"
integrity sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==
-ts-jest@24.2.0:
- version "24.2.0"
- resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.2.0.tgz#7abca28c2b4b0a1fdd715cd667d65d047ea4e768"
- integrity sha512-Yc+HLyldlIC9iIK8xEN7tV960Or56N49MDP7hubCZUeI7EbIOTsas6rXCMB4kQjLACJ7eDOF4xWEO5qumpKsag==
+ts-jest@24.3.0:
+ version "24.3.0"
+ resolved "https://registry.yarnpkg.com/ts-jest/-/ts-jest-24.3.0.tgz#b97814e3eab359ea840a1ac112deae68aa440869"
+ integrity sha512-Hb94C/+QRIgjVZlJyiWwouYUF+siNJHJHknyspaOcZ+OQAIdFG/UrdQVXw/0B8Z3No34xkUXZJpOTy9alOWdVQ==
dependencies:
bs-logger "0.x"
buffer-from "1.x"
@@ -10616,16 +10724,16 @@ ts-loader@5.4.5:
micromatch "^3.1.4"
semver "^5.0.1"
-ts-node@8.5.4:
- version "8.5.4"
- resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.5.4.tgz#a152add11fa19c221d0b48962c210cf467262ab2"
- integrity sha512-izbVCRV68EasEPQ8MSIGBNK9dc/4sYJJKYA+IarMQct1RtEot6Xp0bXuClsbUSnKpg50ho+aOAx8en5c+y4OFw==
+ts-node@8.6.2:
+ version "8.6.2"
+ resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-8.6.2.tgz#7419a01391a818fbafa6f826a33c1a13e9464e35"
+ integrity sha512-4mZEbofxGqLL2RImpe3zMJukvEvcO1XP8bj8ozBPySdCUXEcU5cIRwR0aM3R+VoZq7iXc8N86NC0FspGRqP4gg==
dependencies:
arg "^4.1.0"
diff "^4.0.1"
make-error "^1.1.1"
source-map-support "^0.5.6"
- yn "^3.0.0"
+ yn "3.1.1"
tsconfig-paths-webpack-plugin@3.2.0:
version "3.2.0"
@@ -10707,6 +10815,16 @@ type-fest@^0.5.2:
resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.5.2.tgz#d6ef42a0356c6cd45f49485c3b6281fc148e48a2"
integrity sha512-DWkS49EQKVX//Tbupb9TFa19c7+MK1XmzkrZUR8TAktmE/DizXoaoJV6TZ/tSIPXipqNiRI6CyAe7x69Jb6RSw==
+type-fest@^0.6.0:
+ version "0.6.0"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.6.0.tgz#8d2a2370d3df886eb5c90ada1c5bf6188acf838b"
+ integrity sha512-q+MB8nYR1KDLrgr4G5yemftpMC7/QLqVndBmEEdqzmNj5dcFOO4Oo8qlwZE3ULT3+Zim1F8Kq4cBnikNhlCMlg==
+
+type-fest@^0.8.0, type-fest@^0.8.1:
+ version "0.8.1"
+ resolved "https://registry.yarnpkg.com/type-fest/-/type-fest-0.8.1.tgz#09e249ebde851d3b1e48d27c105444667f17b83d"
+ integrity sha512-4dbzIzqvjtgiM5rw1k5rEHtBANKmdudhGyBEajN01fEyhaAIhsoKNy6y7+IN93IfpFtwY9iqi7kD+xwKhQsNJA==
+
type-is@~1.6.17, type-is@~1.6.18:
version "1.6.18"
resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131"
@@ -11319,6 +11437,13 @@ worker-plugin@3.2.0:
dependencies:
loader-utils "^1.1.0"
+worker-rpc@^0.1.0:
+ version "0.1.1"
+ resolved "https://registry.yarnpkg.com/worker-rpc/-/worker-rpc-0.1.1.tgz#cb565bd6d7071a8f16660686051e969ad32f54d5"
+ integrity sha512-P1WjMrUB3qgJNI9jfmpZ/htmBEjFh//6l/5y8SD9hg1Ef5zTTVVoRjTrTEzPrNBQvmhMxkoTsjOXN10GWU7aCg==
+ dependencies:
+ microevent.ts "~0.1.1"
+
wrap-ansi@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/wrap-ansi/-/wrap-ansi-2.1.0.tgz#d8fc3d284dd05794fe84973caecdd1cf824fdd85"
@@ -11440,7 +11565,7 @@ yargs-parser@10.0.0:
dependencies:
camelcase "^4.1.0"
-yargs-parser@10.x, yargs-parser@^10.0.0:
+yargs-parser@10.x:
version "10.1.0"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-10.1.0.tgz#7202265b89f7e9e9f2e5765e0fe735a905edbaa8"
integrity sha512-VCIyR1wJoEBZUqk5PA+oOBF6ypbwh5aNB3I50guxAL/quggdfs4TtNHQrSazFA3fYZ+tEqfs0zIGlv0c/rgjbQ==
@@ -11463,6 +11588,14 @@ yargs-parser@^13.0.0, yargs-parser@^13.1.1:
camelcase "^5.0.0"
decamelize "^1.2.0"
+yargs-parser@^16.1.0:
+ version "16.1.0"
+ resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-16.1.0.tgz#73747d53ae187e7b8dbe333f95714c76ea00ecf1"
+ integrity sha512-H/V41UNZQPkUMIT5h5hiwg4QKIY1RPvoBV4XcjUbRM8Bk2oKqqyZ0DIEbTFZB0XjbtSPG8SAa/0DxCQmiRgzKg==
+ dependencies:
+ camelcase "^5.0.0"
+ decamelize "^1.2.0"
+
yargs-parser@^9.0.2:
version "9.0.2"
resolved "https://registry.yarnpkg.com/yargs-parser/-/yargs-parser-9.0.2.tgz#9ccf6a43460fe4ed40a9bb68f48d43b8a68cc077"
@@ -11554,7 +11687,7 @@ yauzl@2.4.1:
dependencies:
fd-slicer "~1.0.1"
-yn@^3.0.0:
+yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==