This is an automated email from the ASF dual-hosted git repository.

chanholee pushed a commit to branch branch-0.12
in repository https://gitbox.apache.org/repos/asf/zeppelin.git


The following commit(s) were added to refs/heads/branch-0.12 by this push:
     new 987128808e [ZEPPELIN-6315] Add a lint rule to prevent circular imports 
in zeppelin-web-angular
987128808e is described below

commit 987128808ee09a969b3c28f1d4327bf6bb763d83
Author: ChanHo Lee <chanho...@apache.org>
AuthorDate: Mon Sep 15 23:39:28 2025 +0900

    [ZEPPELIN-6315] Add a lint rule to prevent circular imports in 
zeppelin-web-angular
    
    ### What is this PR for?
    
    Circular imports in JS/TS can make imported symbols unexpectedly 
`undefined` at runtime and also confuse build and tooling. This PR introduces a 
TSLint rule to detect circular imports and refactors imports to prevent them.
    
    - Added `tslint-no-circular-imports` and enabled the rule.
    - Fixed explicit circular-import violations.
    - Standardized import conventions and layering rules to avoid regressions.
    
    #### Import conventions
    
    To keep dependencies simple and acyclic:
    
    1. Cross-module improts -> use the modules's barrel
    Import from the module entry (its public API), not deep files.
    ```ts
    // good
    import { Foo } from '<at>zeppelin/some-module';
    // bad
    import { Foo } from '<at>zeppelin/some-module/feature/foo';
    ```
    - Rationale: reduces tight coupling and ad-hoc interweaving between modules.
    
    2. Intra-module imports -> use relative paths
    Inside the same module, import relatively instead of via that module's 
barrel.
    ```ts
    // good
    import { Bar } from './bar/bar.component';
    // bad
    import { Bar } from '<at>zeppelin/this-module';
    ```
    - Rationale: prevents barrel -> implementation -> barrel loops that often 
create cycles.
    
    > Terminology
    > A "module" here means a directory published via a single alias like 
<at>zeppelin/{module} (one slash).
    
    #### Layering rules
    
    Enforce a single direction of dependencies. This keeps cycles out by 
construction.
    This interpretation aims to minimize disruption to the existing structure. 
If you have alternative proposals, please let me know.
    
    - `core`: framework-agnostic types, tokens, and utilities.
      - Can be used by anyone.
      - Must not depend on `services`, `pages`, or `share`
    - `services`: non-UI logics
      - May depend on `core`.
      - Must not depend on `share` or `pages`.
    - `pages`: May depend on `services`, `share`, and `core`.
    - `share` : presentational componets, directives
      - May depend on `core` and `service`
    
    ### What type of PR is it?
    Refactoring
    
    ### What is the Jira issue?
    [ZEPPELIN-6315](https://issues.apache.org/jira/browse/ZEPPELIN-6315)
    
    ### Questions:
    * Does the license files need to update? No
    * Is there breaking changes for older versions? No
    * Does this needs documentation? No
    
    Closes #5065 from tbonelee/circular-import.
    
    Signed-off-by: ChanHo Lee <chanho...@apache.org>
    (cherry picked from commit 5aa65256ff02c1d5e949892d1f1118e507df513e)
    Signed-off-by: ChanHo Lee <chanho...@apache.org>
---
 zeppelin-web-angular/package-lock.json             | 18 ++++++
 zeppelin-web-angular/package.json                  |  1 +
 .../projects/zeppelin-helium/src/common-deps.ts    |  1 +
 .../zeppelin-sdk/src/interfaces/public-api.ts      |  4 +-
 .../zeppelin-visualization/src/public-api.ts       | 12 ++--
 zeppelin-web-angular/src/app/app.module.ts         |  3 +-
 .../app/core/message-listener/message-listener.ts  |  5 +-
 .../paragraph-base/angular-context-manager.ts}     | 28 +++++----
 .../paragraph-base/note-status.ts}                 |  9 ++-
 .../src/app/core/paragraph-base/paragraph-base.ts  | 68 ++++++++++++----------
 .../src/app/core/paragraph-base/public-api.ts      |  2 +
 zeppelin-web-angular/src/app/core/public-api.ts    |  4 +-
 .../src/app/helium-manager/public-api.ts           |  2 +-
 .../src/app/interfaces/public-api.ts               | 11 ++--
 .../src/app/languages/public-api.ts                |  2 +-
 .../notebook-search/notebook-search.component.ts   |  2 +-
 .../result-item/result-item.component.ts           |  4 +-
 .../notebook/action-bar/action-bar.component.ts    |  7 +--
 .../pages/workspace/notebook/notebook.component.ts |  2 +-
 .../pages/workspace/notebook/notebook.module.ts    |  2 +-
 .../paragraph/code-editor/code-editor.component.ts |  2 +-
 .../notebook/paragraph/paragraph.component.ts      | 22 +++++--
 .../published/paragraph/paragraph.component.ts     | 22 +++++--
 .../pages/workspace/published/published.module.ts  |  2 +-
 .../workspace/share/result/result.component.ts     | 14 +++--
 .../src/app/pages/workspace/share/share.module.ts  |  2 +-
 .../src/app/pages/workspace/workspace.component.ts |  6 +-
 .../src/app/services/array-ordering.service.ts     |  3 +-
 .../src/app/services/ng-z.service.ts               | 13 ++---
 .../src/app/services/note-list.service.ts          |  3 +-
 .../src/app/services/note-status.service.ts        | 10 +---
 .../src/app/services/notebook.service.ts           |  4 +-
 .../src/app/services/public-api.ts                 | 28 ++++-----
 .../src/app/share/code-editor/public-api.ts        |  2 +-
 .../share/folder-rename/folder-rename.component.ts |  3 +-
 .../public-api.ts => share/folder-rename/index.ts} |  3 +-
 .../folder-rename}/public-api.ts                   |  3 +-
 .../src/app/share/header/header.component.ts       |  5 +-
 .../src/app/share/node-list/node-list.component.ts |  8 +--
 .../node-list}/note-action.service.ts              |  8 +--
 .../public-api.ts => share/note-create/index.ts}   |  3 +-
 .../app/share/note-create/note-create.component.ts |  3 +-
 .../{languages => share/note-create}/public-api.ts |  3 +-
 .../public-api.ts => share/note-import/index.ts}   |  3 +-
 .../app/share/note-import/note-import.component.ts |  3 +-
 .../{languages => share/note-import}/public-api.ts |  3 +-
 .../public-api.ts => share/note-rename/index.ts}   |  3 +-
 .../app/share/note-rename/note-rename.component.ts |  2 +-
 .../{languages => share/note-rename}/public-api.ts |  3 +-
 zeppelin-web-angular/src/app/share/public-api.ts   |  6 ++
 zeppelin-web-angular/src/app/share/share.module.ts | 32 +++++-----
 .../public-api.ts => share/shortcut/index.ts}      |  3 +-
 .../{languages => share/shortcut}/public-api.ts    |  3 +-
 .../{languages/public-api.ts => spell/index.ts}    |  3 +-
 .../src/app/{languages => spell}/public-api.ts     |  3 +-
 .../src/app/utility/get-keyword-positions.ts       |  2 +-
 .../{languages/public-api.ts => utility/index.ts}  |  3 +-
 .../app/{helium-manager => utility}/public-api.ts  |  7 ++-
 .../public-api.ts => visualizations/index.ts}      |  3 +-
 .../public-api.ts                                  | 10 +++-
 zeppelin-web-angular/tslint.json                   |  1 +
 61 files changed, 246 insertions(+), 206 deletions(-)

diff --git a/zeppelin-web-angular/package-lock.json 
b/zeppelin-web-angular/package-lock.json
index 1ca44e5d55..3d44383067 100644
--- a/zeppelin-web-angular/package-lock.json
+++ b/zeppelin-web-angular/package-lock.json
@@ -73,6 +73,7 @@
         "ts-node": "~7.0.0",
         "tsickle": "0.38.1",
         "tslint": "~5.15.0",
+        "tslint-no-circular-imports": "^0.7.0",
         "typescript": "3.8.3"
       },
       "engines": {
@@ -19474,6 +19475,16 @@
         "typescript": ">=2.1.0 || >=2.1.0-dev || >=2.2.0-dev || >=2.3.0-dev || 
>=2.4.0-dev || >=2.5.0-dev || >=2.6.0-dev || >=2.7.0-dev || >=2.8.0-dev || 
>=2.9.0-dev || >=3.0.0-dev || >= 3.1.0-dev || >= 3.2.0-dev"
       }
     },
+    "node_modules/tslint-no-circular-imports": {
+      "version": "0.7.0",
+      "resolved": 
"https://registry.npmjs.org/tslint-no-circular-imports/-/tslint-no-circular-imports-0.7.0.tgz";,
+      "integrity": 
"sha512-k3wxpeMC4ef40UbpfBVHEHIzKfNZq5/SCtAO1YjGsaNTklo+K53/TWLrym+poA65RJFDiYgYNWvkeIIkJNA0Vw==",
+      "dev": true,
+      "peerDependencies": {
+        "tslint": ">=5.0.0",
+        "typescript": ">=2.1.0"
+      }
+    },
     "node_modules/tslint/node_modules/builtin-modules": {
       "version": "1.1.1",
       "resolved": 
"https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz";,
@@ -37887,6 +37898,13 @@
         }
       }
     },
+    "tslint-no-circular-imports": {
+      "version": "0.7.0",
+      "resolved": 
"https://registry.npmjs.org/tslint-no-circular-imports/-/tslint-no-circular-imports-0.7.0.tgz";,
+      "integrity": 
"sha512-k3wxpeMC4ef40UbpfBVHEHIzKfNZq5/SCtAO1YjGsaNTklo+K53/TWLrym+poA65RJFDiYgYNWvkeIIkJNA0Vw==",
+      "dev": true,
+      "requires": {}
+    },
     "tsutils": {
       "version": "2.29.0",
       "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-2.29.0.tgz";,
diff --git a/zeppelin-web-angular/package.json 
b/zeppelin-web-angular/package.json
index 9a997c46fd..b12e95bd7d 100644
--- a/zeppelin-web-angular/package.json
+++ b/zeppelin-web-angular/package.json
@@ -86,6 +86,7 @@
     "ts-node": "~7.0.0",
     "tsickle": "0.38.1",
     "tslint": "~5.15.0",
+    "tslint-no-circular-imports": "^0.7.0",
     "typescript": "3.8.3"
   },
   "lint-staged": {
diff --git a/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts 
b/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts
index e10b3ccdd3..989fc06d70 100644
--- a/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts
+++ b/zeppelin-web-angular/projects/zeppelin-helium/src/common-deps.ts
@@ -25,6 +25,7 @@ import * as lodash from 'lodash';
 
 import * as ngZorro from 'ng-zorro-antd';
 import * as tslib from 'tslib';
+// tslint:disable-next-line: no-circular-imports
 import * as zeppelinHelium from './public-api';
 
 export const COMMON_DEPS = {
diff --git 
a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts 
b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts
index 4160fa7f03..fca7b31a31 100644
--- a/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts
+++ b/zeppelin-web-angular/projects/zeppelin-sdk/src/interfaces/public-api.ts
@@ -12,9 +12,9 @@
 
 export * from './message-common.interface';
 export * from './message-data-type-map.interface';
+export * from './message-interpreter.interface';
+export * from './message-job.interface';
 export * from './message-notebook.interface';
 export * from './message-operator.interface';
 export * from './message-paragraph.interface';
 export * from './websocket-message.interface';
-export * from './message-job.interface';
-export * from './message-interpreter.interface';
diff --git 
a/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts 
b/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts
index c28b0e2a64..50d68f86ad 100644
--- a/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts
+++ b/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts
@@ -15,11 +15,11 @@
  */
 
 export * from './data-set';
-export * from './transformation';
-export * from './visualization-component-portal';
-export * from './visualization';
-export * from './table-data';
-export * from './table-transformation';
-export * from './pivot-transformation';
 export * from './g2-visualization-base';
 export * from './g2-visualization-component-base';
+export * from './pivot-transformation';
+export * from './table-data';
+export * from './table-transformation';
+export * from './transformation';
+export * from './visualization';
+export * from './visualization-component-portal';
diff --git a/zeppelin-web-angular/src/app/app.module.ts 
b/zeppelin-web-angular/src/app/app.module.ts
index 61d6dddbd9..7b3f80ceaf 100644
--- a/zeppelin-web-angular/src/app/app.module.ts
+++ b/zeppelin-web-angular/src/app/app.module.ts
@@ -27,9 +27,8 @@ import { NzNotificationService } from 
'ng-zorro-antd/notification';
 import { MESSAGE_INTERCEPTOR, TRASH_FOLDER_ID_TOKEN } from 
'@zeppelin/interfaces';
 import { loadMonacoBefore } from '@zeppelin/languages';
 import { TicketService } from '@zeppelin/services';
-import { ShareModule } from '@zeppelin/share';
+import { JoinedEditorOptions, NZ_CODE_EDITOR_CONFIG, ShareModule } from 
'@zeppelin/share';
 
-import { JoinedEditorOptions, NZ_CODE_EDITOR_CONFIG } from 
'@zeppelin/share/code-editor';
 import { AppHttpInterceptor } from './app-http.interceptor';
 import { AppMessageInterceptor } from './app-message.interceptor';
 import { AppRoutingModule } from './app-routing.module';
diff --git 
a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts 
b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts
index 4a2217bd11..4d6d6c9035 100644
--- a/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts
+++ b/zeppelin-web-angular/src/app/core/message-listener/message-listener.ts
@@ -13,13 +13,12 @@
 import { OnDestroy } from '@angular/core';
 import { Subscriber } from 'rxjs';
 
-import { MessageReceiveDataTypeMap, ReceiveArgumentsType } from 
'@zeppelin/sdk';
-import { MessageService } from '@zeppelin/services';
+import { Message, MessageReceiveDataTypeMap, ReceiveArgumentsType } from 
'@zeppelin/sdk';
 
 export class MessageListenersManager implements OnDestroy {
   __zeppelinMessageListeners__?: Array<() => void>;
   __zeppelinMessageListeners$__: Subscriber<unknown> | null = new Subscriber();
-  constructor(public messageService: MessageService) {
+  constructor(public messageService: Message) {
     if (this.__zeppelinMessageListeners__) {
       this.__zeppelinMessageListeners__.forEach(fn => fn.apply(this));
     }
diff --git 
a/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts 
b/zeppelin-web-angular/src/app/core/paragraph-base/angular-context-manager.ts
similarity index 52%
copy from zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts
copy to 
zeppelin-web-angular/src/app/core/paragraph-base/angular-context-manager.ts
index c28b0e2a64..beaa990898 100644
--- a/zeppelin-web-angular/projects/zeppelin-visualization/src/public-api.ts
+++ 
b/zeppelin-web-angular/src/app/core/paragraph-base/angular-context-manager.ts
@@ -10,16 +10,20 @@
  * limitations under the License.
  */
 
-/*
- * Public API Surface of zeppelin-visualization
- */
+import { Observable } from 'rxjs';
+
+export interface AngularContext {
+  paragraphId: string;
+  key: string;
+  // tslint:disable-next-line:no-any
+  value: any;
+  emit: boolean;
+  set: boolean;
+}
 
-export * from './data-set';
-export * from './transformation';
-export * from './visualization-component-portal';
-export * from './visualization';
-export * from './table-data';
-export * from './table-transformation';
-export * from './pivot-transformation';
-export * from './g2-visualization-base';
-export * from './g2-visualization-component-base';
+export interface AngularContextManager {
+  setContextValue(key: string, value: unknown, paragraphId: string, emit?: 
boolean): void;
+  unsetContextValue(key: string, paragraphId: string, emit?: boolean): unknown;
+  contextChanged(): Observable<AngularContext>;
+  runParagraphAction(): Observable<string>;
+}
diff --git a/zeppelin-web-angular/src/app/helium-manager/public-api.ts 
b/zeppelin-web-angular/src/app/core/paragraph-base/note-status.ts
similarity index 72%
copy from zeppelin-web-angular/src/app/helium-manager/public-api.ts
copy to zeppelin-web-angular/src/app/core/paragraph-base/note-status.ts
index 8ba1a21026..9cb603b4fc 100644
--- a/zeppelin-web-angular/src/app/helium-manager/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/note-status.ts
@@ -10,5 +10,10 @@
  * limitations under the License.
  */
 
-export * from './helium-manager.service';
-export * from './helium-manager.module';
+import { Note, ParagraphItem } from '@zeppelin/sdk';
+
+export interface NoteStatus {
+  isParagraphRunning(paragraph: ParagraphItem): boolean;
+
+  isEntireNoteRunning(note: Exclude<Note['note'], undefined>): boolean;
+}
diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts 
b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts
index d70741c9d4..85a59ec343 100644
--- a/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/paragraph-base.ts
@@ -10,30 +10,38 @@
  * limitations under the License.
  */
 
-import { ChangeDetectorRef, QueryList } from '@angular/core';
-
+import { ChangeDetectorRef } from '@angular/core';
 import {
   AngularObjectRemove,
   AngularObjectUpdate,
   GraphConfig,
+  Message,
   MessageReceiveDataTypeMap,
   OP,
   ParagraphConfig,
+  ParagraphConfigResult,
+  ParagraphConfigResults,
   ParagraphEditorSetting,
   ParagraphItem,
-  ParagraphIResultsMsgItem
+  ParagraphIResultsMsgItem,
+  ParagraphResults
 } from '@zeppelin/sdk';
 
-import { MessageService } from '@zeppelin/services/message.service';
-import { NgZService } from '@zeppelin/services/ng-z.service';
-import { NoteStatusService, ParagraphStatus } from 
'@zeppelin/services/note-status.service';
-
 import * as DiffMatchPatch from 'diff-match-patch';
 import { isEmpty, isEqual } from 'lodash';
 
-import { NotebookParagraphResultComponent } from 
'@zeppelin/pages/workspace/share/result/result.component';
-import { ParagraphConfigResults, ParagraphResults } from 
'../../../../projects/zeppelin-sdk/src';
 import { MessageListener, MessageListenersManager } from 
'../message-listener/message-listener';
+import { AngularContextManager } from './angular-context-manager';
+import { NoteStatus } from './note-status';
+
+export const ParagraphStatus = {
+  READY: 'READY',
+  PENDING: 'PENDING',
+  RUNNING: 'RUNNING',
+  FINISHED: 'FINISHED',
+  ABORT: 'ABORT',
+  ERROR: 'ERROR'
+};
 
 export abstract class ParagraphBase extends MessageListenersManager {
   paragraph?: ParagraphItem;
@@ -52,13 +60,10 @@ export abstract class ParagraphBase extends 
MessageListenersManager {
     forms: {}
   };
 
-  // Initialized by `ViewChildren` in the class which extends ParagraphBase
-  notebookParagraphResultComponents!: 
QueryList<NotebookParagraphResultComponent>;
-
   constructor(
-    public messageService: MessageService,
-    protected noteStatusService: NoteStatusService,
-    protected ngZService: NgZService,
+    public messageService: Message,
+    protected noteStatusService: NoteStatus,
+    protected angularContextManager: AngularContextManager,
     protected cdr: ChangeDetectorRef
   ) {
     super(messageService);
@@ -123,22 +128,15 @@ export abstract class ParagraphBase extends 
MessageListenersManager {
     if (this.isUpdateRequired(oldPara, newPara)) {
       this.updateParagraph(oldPara, newPara, () => {
         if (newPara.results && newPara.results.msg) {
-          // tslint:disable-next-line:no-for-in-array
-          for (const i in newPara.results.msg) {
-            if (newPara.results.msg[i]) {
-              const newResult = newPara.results.msg ? newPara.results.msg[i] : 
new ParagraphIResultsMsgItem();
-              const oldResult =
-                oldPara.results && oldPara.results.msg ? 
oldPara.results.msg[i] : new ParagraphIResultsMsgItem();
-              const newConfig = newPara.config.results ? 
newPara.config.results[i] : { graph: new GraphConfig() };
-              const oldConfig = oldPara.config.results ? 
oldPara.config.results[i] : { graph: new GraphConfig() };
-              if (!isEqual(newResult, oldResult) || !isEqual(newConfig, 
oldConfig)) {
-                const resultComponent = 
this.notebookParagraphResultComponents.toArray()[i];
-                if (resultComponent) {
-                  resultComponent.updateResult(newConfig, newResult);
-                }
-              }
+          newPara.results.msg.forEach((newResult, idx) => {
+            const oldResult =
+              oldPara.results && oldPara.results.msg ? 
oldPara.results.msg[idx] : new ParagraphIResultsMsgItem();
+            const newConfig = newPara.config.results ? 
newPara.config.results[idx] : { graph: new GraphConfig() };
+            const oldConfig = oldPara.config.results ? 
oldPara.config.results[idx] : { graph: new GraphConfig() };
+            if (!isEqual(newResult, oldResult) || !isEqual(newConfig, 
oldConfig)) {
+              this.updateParagraphResult(idx, newConfig, newResult);
             }
-          }
+          });
         }
         this.cdr.markForCheck();
       });
@@ -146,6 +144,12 @@ export abstract class ParagraphBase extends 
MessageListenersManager {
     }
   }
 
+  abstract updateParagraphResult(
+    resultIndex: number,
+    config: ParagraphConfigResult,
+    result: ParagraphIResultsMsgItem
+  ): void;
+
   @MessageListener(OP.PATCH_PARAGRAPH)
   patchParagraph(data: MessageReceiveDataTypeMap[OP.PATCH_PARAGRAPH]) {
     if (!this.paragraph) {
@@ -169,7 +173,7 @@ export abstract class ParagraphBase extends 
MessageListenersManager {
     }
     if (data.paragraphId === this.paragraph.id) {
       const { name, object } = data.angularObject;
-      this.ngZService.setContextValue(name, object, data.paragraphId, false);
+      this.angularContextManager.setContextValue(name, object, 
data.paragraphId, false);
     }
   }
 
@@ -179,7 +183,7 @@ export abstract class ParagraphBase extends 
MessageListenersManager {
       throw new Error('paragraph is not defined');
     }
     if (data.paragraphId === this.paragraph.id) {
-      this.ngZService.unsetContextValue(data.name, data.paragraphId, false);
+      this.angularContextManager.unsetContextValue(data.name, 
data.paragraphId, false);
     }
   }
 
diff --git a/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts 
b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
index a6ba53216e..ea42b0baae 100644
--- a/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/paragraph-base/public-api.ts
@@ -10,5 +10,7 @@
  * limitations under the License.
  */
 
+export * from './angular-context-manager';
+export * from './note-status';
 export * from './paragraph-base';
 export * from './published';
diff --git a/zeppelin-web-angular/src/app/core/public-api.ts 
b/zeppelin-web-angular/src/app/core/public-api.ts
index 3f334c803b..73b03719a6 100644
--- a/zeppelin-web-angular/src/app/core/public-api.ts
+++ b/zeppelin-web-angular/src/app/core/public-api.ts
@@ -10,8 +10,8 @@
  * limitations under the License.
  */
 
-export * from './message-listener';
-export * from './destroy-hook';
 export * from './copy-text';
+export * from './destroy-hook';
+export * from './message-listener';
 export * from './paragraph-base';
 export * from './runtime-dynamic-module';
diff --git a/zeppelin-web-angular/src/app/helium-manager/public-api.ts 
b/zeppelin-web-angular/src/app/helium-manager/public-api.ts
index 8ba1a21026..9f0df57258 100644
--- a/zeppelin-web-angular/src/app/helium-manager/public-api.ts
+++ b/zeppelin-web-angular/src/app/helium-manager/public-api.ts
@@ -10,5 +10,5 @@
  * limitations under the License.
  */
 
-export * from './helium-manager.service';
 export * from './helium-manager.module';
+export * from './helium-manager.service';
diff --git a/zeppelin-web-angular/src/app/interfaces/public-api.ts 
b/zeppelin-web-angular/src/app/interfaces/public-api.ts
index 7e15c29918..f5d5ae5e25 100644
--- a/zeppelin-web-angular/src/app/interfaces/public-api.ts
+++ b/zeppelin-web-angular/src/app/interfaces/public-api.ts
@@ -10,11 +10,12 @@
  * limitations under the License.
  */
 
-export * from './ticket';
-export * from './trash-folder-id';
+export * from './credential';
 export * from './interpreter';
 export * from './message-interceptor';
-export * from './security';
-export * from './credential';
-export * from './notebook-repo';
+export * from './node-list';
 export * from './notebook';
+export * from './notebook-repo';
+export * from './security';
+export * from './ticket';
+export * from './trash-folder-id';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/languages/public-api.ts
index 973c93158b..bbe6ba19cb 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/languages/public-api.ts
@@ -10,5 +10,5 @@
  * limitations under the License.
  */
 
-export * from './scala';
 export * from './load';
+export * from './scala';
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts
index 1269a5bcd4..dc46efa31f 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/notebook-search.component.ts
@@ -13,7 +13,7 @@
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnDestroy, 
OnInit } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import { NotebookSearchResultItem } from '@zeppelin/interfaces';
-import { NotebookService } from '@zeppelin/services/notebook.service';
+import { NotebookService } from '@zeppelin/services';
 import { Subject } from 'rxjs';
 import { filter, map, switchMap, takeUntil, tap } from 'rxjs/operators';
 
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts
index 339a2a3f19..60e734900a 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook-search/result-item/result-item.component.ts
@@ -22,8 +22,8 @@ import {
 } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
 import { NotebookSearchResultItem } from '@zeppelin/interfaces';
-import { JoinedEditorOptions } from '@zeppelin/share/code-editor';
-import { getKeywordPositions, KeywordPosition } from 
'@zeppelin/utility/get-keyword-positions';
+import { JoinedEditorOptions } from '@zeppelin/share';
+import { getKeywordPositions, KeywordPosition } from '@zeppelin/utility';
 import { editor, Range } from 'monaco-editor';
 import IEditor = editor.IEditor;
 import IStandaloneCodeEditor = editor.IStandaloneCodeEditor;
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts
index fe2f92ec33..a7adbaceb3 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/action-bar/action-bar.component.ts
@@ -27,11 +27,8 @@ import { NzModalService } from 'ng-zorro-antd/modal';
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces';
 import { MessageReceiveDataTypeMap, Note, OP, RevisionListItem } from 
'@zeppelin/sdk';
-import { MessageService, NoteStatusService, SaveAsService, TicketService } 
from '@zeppelin/services';
-
-import { NotebookService } from '@zeppelin/services/notebook.service';
-import { NoteCreateComponent } from 
'@zeppelin/share/note-create/note-create.component';
-import { ShortcutComponent } from 
'@zeppelin/share/shortcut/shortcut.component';
+import { MessageService, NotebookService, NoteStatusService, SaveAsService, 
TicketService } from '@zeppelin/services';
+import { NoteCreateComponent, ShortcutComponent } from '@zeppelin/share';
 
 @Component({
   selector: 'zeppelin-notebook-action-bar',
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
index 57e5b20749..a9e7d6d968 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.component.ts
@@ -46,7 +46,7 @@ import {
   TicketService
 } from '@zeppelin/services';
 
-import { scrollIntoViewIfNeeded } from '@zeppelin/utility/element';
+import { scrollIntoViewIfNeeded } from '@zeppelin/utility';
 import { NotebookParagraphComponent } from './paragraph/paragraph.component';
 
 @Component({
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
index 8b1a62e8e0..a50e07ff2d 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/notebook/notebook.module.ts
@@ -47,7 +47,7 @@ import { NotebookPermissionsComponent } from 
'./permissions/permissions.componen
 import { NotebookRevisionsComparatorComponent } from 
'./revisions-comparator/revisions-comparator.component';
 
 import { NzCheckboxModule } from 'ng-zorro-antd/checkbox';
-import { WorkspaceShareModule } from '../../workspace/share/share.module';
+import { WorkspaceShareModule } from '../share/share.module';
 import { NotebookActionBarComponent } from './action-bar/action-bar.component';
 import { NoteFormBlockComponent } from 
'./note-form-block/note-form-block.component';
 import { NotebookRoutingModule } from './notebook-routing.module';
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
index fdbc3f37d0..d162af28a0 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/code-editor/code-editor.component.ts
@@ -28,7 +28,7 @@ import { editor as MonacoEditor, IDisposable, IPosition, 
KeyCode, Position } fro
 import { InterpreterBindingItem } from '@zeppelin/sdk';
 import { CompletionService, MessageService } from '@zeppelin/services';
 
-import { pt2px } from '@zeppelin/utility/css-unit-conversion';
+import { pt2px } from '@zeppelin/utility';
 import { NotebookParagraphControlComponent } from 
'../control/control.component';
 
 type IStandaloneCodeEditor = MonacoEditor.IStandaloneCodeEditor;
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
index bdd6adfb05..0ee3171f4b 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/notebook/paragraph/paragraph.component.ts
@@ -33,7 +33,13 @@ import { map, takeUntil } from 'rxjs/operators';
 import { NzModalService } from 'ng-zorro-antd/modal';
 
 import { ParagraphBase } from '@zeppelin/core';
-import { InterpreterBindingItem, Note, ParagraphConfigResult, ParagraphItem } 
from '@zeppelin/sdk';
+import {
+  InterpreterBindingItem,
+  Note,
+  ParagraphConfigResult,
+  ParagraphItem,
+  ParagraphIResultsMsgItem
+} from '@zeppelin/sdk';
 import {
   HeliumService,
   MessageService,
@@ -44,7 +50,7 @@ import {
   ShortcutsMap,
   ShortcutService
 } from '@zeppelin/services';
-import { SpellResult } from '@zeppelin/spell/spell-result';
+import { SpellResult } from '@zeppelin/spell';
 
 import { NzResizeEvent } from 'ng-zorro-antd/resizable';
 import { NotebookParagraphResultComponent } from 
'../../share/result/result.component';
@@ -87,9 +93,17 @@ export class NotebookParagraphComponent extends 
ParagraphBase implements OnInit,
   @Output() readonly searchCode = new EventEmitter();
 
   private destroy$ = new Subject();
+
   private mode: Mode = 'command';
   waitConfirmFromEdit = false;
 
+  updateParagraphResult(resultIndex: number, config: ParagraphConfigResult, 
result: ParagraphIResultsMsgItem): void {
+    const resultComponent = 
this.notebookParagraphResultComponents.toArray()[resultIndex];
+    if (resultComponent) {
+      resultComponent.updateResult(config, result);
+    }
+  }
+
   switchMode(mode: Mode): void {
     if (mode === this.mode) {
       return;
@@ -623,7 +637,7 @@ export class NotebookParagraphComponent extends 
ParagraphBase implements OnInit,
     this.isParagraphRunning = 
this.noteStatusService.isParagraphRunning(this.paragraph);
     this.noteVarShareService.set(this.paragraph.id + '_paragraphScope', this);
     this.initializeDefault(this.paragraph.config, this.paragraph.settings);
-    this.ngZService
+    this.angularContextManager
       .runParagraphAction()
       .pipe(takeUntil(this.destroy$))
       .subscribe(id => {
@@ -631,7 +645,7 @@ export class NotebookParagraphComponent extends 
ParagraphBase implements OnInit,
           this.runParagraph();
         }
       });
-    this.ngZService
+    this.angularContextManager
       .contextChanged()
       .pipe(takeUntil(this.destroy$))
       .subscribe(change => {
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
 
b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
index 73ec31380a..b7be6c4292 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/published/paragraph/paragraph.component.ts
@@ -11,13 +11,18 @@
  */
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit, 
QueryList, ViewChildren } from '@angular/core';
 import { ActivatedRoute } from '@angular/router';
-import { MessageListener, ParagraphBase } from '@zeppelin/core';
-import { publishedSymbol, Published } from 
'@zeppelin/core/paragraph-base/published';
-import { NotebookParagraphResultComponent } from 
'@zeppelin/pages/workspace/share/result/result.component';
-import { MessageReceiveDataTypeMap, OP, ParagraphItem } from '@zeppelin/sdk';
+import { publishedSymbol, MessageListener, ParagraphBase, Published } from 
'@zeppelin/core';
+import {
+  MessageReceiveDataTypeMap,
+  OP,
+  ParagraphConfigResult,
+  ParagraphItem,
+  ParagraphIResultsMsgItem
+} from '@zeppelin/sdk';
 import { HeliumService, MessageService, NgZService, NoteStatusService } from 
'@zeppelin/services';
-import { SpellResult } from '@zeppelin/spell/spell-result';
+import { SpellResult } from '@zeppelin/spell';
 import { isNil } from 'lodash';
+import { NotebookParagraphResultComponent } from 
'../../share/result/result.component';
 
 @Component({
   selector: 'zeppelin-publish-paragraph',
@@ -102,4 +107,11 @@ export class PublishedParagraphComponent extends 
ParagraphBase implements Publis
       }
     }
   }
+
+  updateParagraphResult(resultIndex: number, config: ParagraphConfigResult, 
result: ParagraphIResultsMsgItem): void {
+    const resultComponent = 
this.notebookParagraphResultComponents.toArray()[resultIndex];
+    if (resultComponent) {
+      resultComponent.updateResult(config, result);
+    }
+  }
 }
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts 
b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts
index 6b061c35e3..236b9b2ac3 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/published/published.module.ts
@@ -12,7 +12,7 @@
 
 import { CommonModule } from '@angular/common';
 import { NgModule } from '@angular/core';
-import { WorkspaceShareModule } from '../../workspace/share/share.module';
+import { WorkspaceShareModule } from '../share/share.module';
 import { PublishedParagraphComponent } from './paragraph/paragraph.component';
 import { PublishedRoutingModule } from './published-ruoting.module';
 
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts 
b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
index bcbc761afa..489cc783f6 100644
--- 
a/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
+++ 
b/zeppelin-web-angular/src/app/pages/workspace/share/result/result.component.ts
@@ -51,12 +51,14 @@ import { TableData, Visualization } from 
'@zeppelin/visualization';
 
 import { HeliumManagerService } from '@zeppelin/helium-manager';
 import { DynamicTemplate, NgZService, RuntimeCompilerService } from 
'@zeppelin/services';
-import { AreaChartVisualization } from 
'@zeppelin/visualizations/area-chart/area-chart-visualization';
-import { BarChartVisualization } from 
'@zeppelin/visualizations/bar-chart/bar-chart-visualization';
-import { LineChartVisualization } from 
'@zeppelin/visualizations/line-chart/line-chart-visualization';
-import { PieChartVisualization } from 
'@zeppelin/visualizations/pie-chart/pie-chart-visualization';
-import { ScatterChartVisualization } from 
'@zeppelin/visualizations/scatter-chart/scatter-chart-visualization';
-import { TableVisualization } from 
'@zeppelin/visualizations/table/table-visualization';
+import {
+  AreaChartVisualization,
+  BarChartVisualization,
+  LineChartVisualization,
+  PieChartVisualization,
+  ScatterChartVisualization,
+  TableVisualization
+} from '@zeppelin/visualizations';
 
 @Component({
   selector: 'zeppelin-notebook-paragraph-result',
diff --git a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts 
b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
index dfc2c4c5ba..4d1b8122e9 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/share/share.module.ts
@@ -28,7 +28,7 @@ import { NzSwitchModule } from 'ng-zorro-antd/switch';
 import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
 
 import { ShareModule } from '@zeppelin/share';
-import { VisualizationModule } from 
'@zeppelin/visualizations/visualization.module';
+import { VisualizationModule } from '@zeppelin/visualizations';
 
 import { NotebookParagraphDynamicFormsComponent } from 
'./dynamic-forms/dynamic-forms.component';
 import { NotebookParagraphResultComponent } from './result/result.component';
diff --git 
a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts 
b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
index 3b1558c4f7..2d08a7ee8a 100644
--- a/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
+++ b/zeppelin-web-angular/src/app/pages/workspace/workspace.component.ts
@@ -11,14 +11,14 @@
  */
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, 
OnDestroy, OnInit } from '@angular/core';
-import { isRecord } from '@zeppelin/utility/type-utility';
+import { publishedSymbol } from '@zeppelin/core';
+import { isRecord } from '@zeppelin/utility';
 import { Subject } from 'rxjs';
 import { takeUntil } from 'rxjs/operators';
 
-import { publishedSymbol } from '@zeppelin/core/paragraph-base/published';
 import { HeliumManagerService } from '@zeppelin/helium-manager';
 import { MessageService } from '@zeppelin/services';
-import { setTheme } from '@zeppelin/visualizations/g2.config';
+import { setTheme } from '@zeppelin/visualizations';
 import { NzMessageService } from 'ng-zorro-antd/message';
 
 @Component({
diff --git a/zeppelin-web-angular/src/app/services/array-ordering.service.ts 
b/zeppelin-web-angular/src/app/services/array-ordering.service.ts
index 36f4b21409..dc7fb62c44 100644
--- a/zeppelin-web-angular/src/app/services/array-ordering.service.ts
+++ b/zeppelin-web-angular/src/app/services/array-ordering.service.ts
@@ -11,8 +11,7 @@
  */
 
 import { Inject, Injectable } from '@angular/core';
-import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces';
-import { NodeItem } from '@zeppelin/interfaces/node-list';
+import { NodeItem, TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces';
 
 @Injectable({
   providedIn: 'root'
diff --git a/zeppelin-web-angular/src/app/services/ng-z.service.ts 
b/zeppelin-web-angular/src/app/services/ng-z.service.ts
index 51184253bc..1c61eb0cc6 100644
--- a/zeppelin-web-angular/src/app/services/ng-z.service.ts
+++ b/zeppelin-web-angular/src/app/services/ng-z.service.ts
@@ -11,7 +11,9 @@
  */
 
 import { Injectable, OnDestroy } from '@angular/core';
-import { isRecord } from '@zeppelin/utility/type-utility';
+
+import { AngularContext } from '@zeppelin/core';
+import { isRecord } from '@zeppelin/utility';
 import { Subject } from 'rxjs';
 
 @Injectable({
@@ -19,14 +21,7 @@ import { Subject } from 'rxjs';
 })
 export class NgZService implements OnDestroy {
   private paragraphMap: Map<string, unknown> = new Map<string, {}>();
-  private contextChange$ = new Subject<{
-    paragraphId: string;
-    key: string;
-    // tslint:disable-next-line:no-any
-    value: any;
-    emit: boolean;
-    set: boolean;
-  }>();
+  private contextChange$ = new Subject<AngularContext>();
   private runParagraph$ = new Subject<string>();
 
   constructor() {}
diff --git a/zeppelin-web-angular/src/app/services/note-list.service.ts 
b/zeppelin-web-angular/src/app/services/note-list.service.ts
index e8fdcea2ce..a66f45adf8 100644
--- a/zeppelin-web-angular/src/app/services/note-list.service.ts
+++ b/zeppelin-web-angular/src/app/services/note-list.service.ts
@@ -12,10 +12,9 @@
 
 import { Inject, Injectable } from '@angular/core';
 
-import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces';
+import { NodeItem, NodeList, TRASH_FOLDER_ID_TOKEN } from 
'@zeppelin/interfaces';
 import { NotesInfoItem } from '@zeppelin/sdk';
 
-import { NodeItem, NodeList } from '../interfaces/node-list';
 import { ArrayOrderingService } from './array-ordering.service';
 
 @Injectable({
diff --git a/zeppelin-web-angular/src/app/services/note-status.service.ts 
b/zeppelin-web-angular/src/app/services/note-status.service.ts
index eb634aaca8..153da21ca9 100644
--- a/zeppelin-web-angular/src/app/services/note-status.service.ts
+++ b/zeppelin-web-angular/src/app/services/note-status.service.ts
@@ -12,18 +12,10 @@
 
 import { Inject, Injectable } from '@angular/core';
 
+import { ParagraphStatus } from '@zeppelin/core';
 import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces';
 import { Note, ParagraphItem } from '@zeppelin/sdk';
 
-export const ParagraphStatus = {
-  READY: 'READY',
-  PENDING: 'PENDING',
-  RUNNING: 'RUNNING',
-  FINISHED: 'FINISHED',
-  ABORT: 'ABORT',
-  ERROR: 'ERROR'
-};
-
 @Injectable({
   providedIn: 'root'
 })
diff --git a/zeppelin-web-angular/src/app/services/notebook.service.ts 
b/zeppelin-web-angular/src/app/services/notebook.service.ts
index ac4c825d3d..41e64994b1 100644
--- a/zeppelin-web-angular/src/app/services/notebook.service.ts
+++ b/zeppelin-web-angular/src/app/services/notebook.service.ts
@@ -14,9 +14,9 @@ import { HttpClient } from '@angular/common/http';
 import { Injectable } from '@angular/core';
 
 import { NotebookCapabilities, NotebookSearchResultItem } from 
'@zeppelin/interfaces';
-import { BaseRest } from '@zeppelin/services/base-rest';
-import { BaseUrlService } from '@zeppelin/services/base-url.service';
 import { BehaviorSubject } from 'rxjs';
+import { BaseRest } from './base-rest';
+import { BaseUrlService } from './base-url.service';
 
 @Injectable({
   providedIn: 'root'
diff --git a/zeppelin-web-angular/src/app/services/public-api.ts 
b/zeppelin-web-angular/src/app/services/public-api.ts
index f9bdfe9554..e14be4a47d 100644
--- a/zeppelin-web-angular/src/app/services/public-api.ts
+++ b/zeppelin-web-angular/src/app/services/public-api.ts
@@ -10,23 +10,23 @@
  * limitations under the License.
  */
 
+export * from './array-ordering.service';
 export * from './base-url.service';
-export * from './ticket.service';
-export * from './message.service';
-export * from './job-manager.service';
-export * from './interpreter.service';
-export * from './security.service';
-export * from './note-status.service';
-export * from './save-as.service';
-export * from './helium.service';
-export * from './note-var-share.service';
-export * from './note-action.service';
 export * from './completion.service';
+export * from './configuration.service';
+export * from './credential.service';
+export * from './helium.service';
+export * from './interpreter.service';
+export * from './job-manager.service';
+export * from './message.service';
 export * from './ng-z.service';
-export * from './array-ordering.service';
 export * from './note-list.service';
+export * from './note-status.service';
+export * from './note-var-share.service';
+export * from './notebook-repos.service';
+export * from './notebook.service';
 export * from './runtime-compiler.service';
+export * from './save-as.service';
+export * from './security.service';
 export * from './shortcut.service';
-export * from './configuration.service';
-export * from './credential.service';
-export * from './notebook-repos.service';
+export * from './ticket.service';
diff --git a/zeppelin-web-angular/src/app/share/code-editor/public-api.ts 
b/zeppelin-web-angular/src/app/share/code-editor/public-api.ts
index b2144c936c..489e1190ce 100644
--- a/zeppelin-web-angular/src/app/share/code-editor/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/code-editor/public-api.ts
@@ -10,7 +10,7 @@
  * limitations under the License.
  */
 
-export * from './nz-code-editor.definitions';
 export * from './code-editor.component';
 export * from './code-editor.module';
 export * from './code-editor.service';
+export * from './nz-code-editor.definitions';
diff --git 
a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts 
b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts
index 4dfce148b6..961a2d3bbd 100644
--- 
a/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts
+++ 
b/zeppelin-web-angular/src/app/share/folder-rename/folder-rename.component.ts
@@ -14,8 +14,7 @@ import { ChangeDetectionStrategy, ChangeDetectorRef, 
Component, Input, OnInit }
 
 import { NzModalRef } from 'ng-zorro-antd/modal';
 
-import { MessageService } from '@zeppelin/services/message.service';
-import { NoteListService } from '@zeppelin/services/note-list.service';
+import { MessageService, NoteListService } from '@zeppelin/services';
 
 @Component({
   selector: 'zeppelin-folder-rename',
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/folder-rename/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/folder-rename/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/folder-rename/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/folder-rename/public-api.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/folder-rename/public-api.ts
index 973c93158b..2123a0c60e 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/folder-rename/public-api.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './folder-rename.component';
diff --git a/zeppelin-web-angular/src/app/share/header/header.component.ts 
b/zeppelin-web-angular/src/app/share/header/header.component.ts
index 78a7da185f..5dbb14f9b3 100644
--- a/zeppelin-web-angular/src/app/share/header/header.component.ts
+++ b/zeppelin-web-angular/src/app/share/header/header.component.ts
@@ -19,9 +19,8 @@ import { filter, takeUntil } from 'rxjs/operators';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk';
-import { MessageService, TicketService } from '@zeppelin/services';
-import { NotebookService } from '@zeppelin/services/notebook.service';
-import { AboutZeppelinComponent } from 
'@zeppelin/share/about-zeppelin/about-zeppelin.component';
+import { MessageService, NotebookService, TicketService } from 
'@zeppelin/services';
+import { AboutZeppelinComponent } from 
'../about-zeppelin/about-zeppelin.component';
 
 @Component({
   selector: 'zeppelin-header',
diff --git 
a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts 
b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts
index ca40098241..b7bb21406c 100644
--- a/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts
+++ b/zeppelin-web-angular/src/app/share/node-list/node-list.component.ts
@@ -11,15 +11,14 @@
  */
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, 
OnInit } from '@angular/core';
-import { TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces';
-import { NodeItem } from '@zeppelin/interfaces/node-list';
+import { NodeItem, TRASH_FOLDER_ID_TOKEN } from '@zeppelin/interfaces';
 
-import { NzModalService } from 'ng-zorro-antd/modal';
 import { NzTreeNode, NzTreeNodeOptions } from 'ng-zorro-antd/tree';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { MessageReceiveDataTypeMap, OP } from '@zeppelin/sdk';
-import { MessageService, NoteActionService, NoteListService } from 
'@zeppelin/services';
+import { MessageService, NoteListService } from '@zeppelin/services';
+import { NoteActionService } from './note-action.service';
 
 @Component({
   selector: 'zeppelin-node-list',
@@ -138,7 +137,6 @@ export class NodeListComponent extends 
MessageListenersManager implements OnInit
     public messageService: MessageService,
     @Inject(TRASH_FOLDER_ID_TOKEN) public TRASH_FOLDER_ID: string,
     private noteListService: NoteListService,
-    private nzModalService: NzModalService,
     private noteActionService: NoteActionService,
     private cdr: ChangeDetectorRef
   ) {
diff --git a/zeppelin-web-angular/src/app/services/note-action.service.ts 
b/zeppelin-web-angular/src/app/share/node-list/note-action.service.ts
similarity index 83%
rename from zeppelin-web-angular/src/app/services/note-action.service.ts
rename to zeppelin-web-angular/src/app/share/node-list/note-action.service.ts
index 44e0ca8861..433f991e71 100644
--- a/zeppelin-web-angular/src/app/services/note-action.service.ts
+++ b/zeppelin-web-angular/src/app/share/node-list/note-action.service.ts
@@ -14,10 +14,10 @@ import { Injectable } from '@angular/core';
 
 import { NzModalService } from 'ng-zorro-antd/modal';
 
-import { FolderRenameComponent } from 
'@zeppelin/share/folder-rename/folder-rename.component';
-import { NoteCreateComponent } from 
'@zeppelin/share/note-create/note-create.component';
-import { NoteImportComponent } from 
'@zeppelin/share/note-import/note-import.component';
-import { NoteRenameComponent } from 
'@zeppelin/share/note-rename/note-rename.component';
+import { FolderRenameComponent } from 
'../folder-rename/folder-rename.component';
+import { NoteCreateComponent } from '../note-create/note-create.component';
+import { NoteImportComponent } from '../note-import/note-import.component';
+import { NoteRenameComponent } from '../note-rename/note-rename.component';
 
 @Injectable({
   providedIn: 'root'
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/note-create/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/note-create/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/note-create/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git 
a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts 
b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts
index ab0c7688ce..13e1b89a52 100644
--- a/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts
+++ b/zeppelin-web-angular/src/app/share/note-create/note-create.component.ts
@@ -11,13 +11,12 @@
  */
 
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnInit 
} from '@angular/core';
+import { MessageService, NoteListService } from '@zeppelin/services';
 
 import { NzModalRef } from 'ng-zorro-antd/modal';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { InterpreterItem, MessageReceiveDataTypeMap, Note, OP } from 
'@zeppelin/sdk';
-import { MessageService } from '@zeppelin/services/message.service';
-import { NoteListService } from '@zeppelin/services/note-list.service';
 
 @Component({
   selector: 'zeppelin-note-create',
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/note-create/public-api.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/note-create/public-api.ts
index 973c93158b..be63e7f60d 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/note-create/public-api.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './note-create.component';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/note-import/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/note-import/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/note-import/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git 
a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts 
b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts
index 32294cb5ee..f73fe7f9ec 100644
--- a/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts
+++ b/zeppelin-web-angular/src/app/share/note-import/note-import.component.ts
@@ -12,6 +12,7 @@
 
 import { HttpClient } from '@angular/common/http';
 import { ChangeDetectionStrategy, ChangeDetectorRef, Component, OnInit } from 
'@angular/core';
+import { MessageService, TicketService } from '@zeppelin/services';
 
 import { get } from 'lodash';
 import { NzModalRef } from 'ng-zorro-antd/modal';
@@ -19,8 +20,6 @@ import { NzUploadFile } from 'ng-zorro-antd/upload';
 
 import { MessageListener, MessageListenersManager } from '@zeppelin/core';
 import { MessageReceiveDataTypeMap, OP, SendNote } from '@zeppelin/sdk';
-import { MessageService } from '@zeppelin/services/message.service';
-import { TicketService } from '@zeppelin/services/ticket.service';
 
 @Component({
   selector: 'zeppelin-note-import',
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/note-import/public-api.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/note-import/public-api.ts
index 973c93158b..00309e19ab 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/note-import/public-api.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './note-import.component';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/note-rename/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/note-rename/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/note-rename/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git 
a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts 
b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts
index 9f8cfe914a..4743fe45c9 100644
--- a/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts
+++ b/zeppelin-web-angular/src/app/share/note-rename/note-rename.component.ts
@@ -14,7 +14,7 @@ import { ChangeDetectionStrategy, Component, Input, OnInit } 
from '@angular/core
 
 import { NzModalRef } from 'ng-zorro-antd/modal';
 
-import { MessageService } from '@zeppelin/services/message.service';
+import { MessageService } from '@zeppelin/services';
 
 @Component({
   selector: 'zeppelin-note-rename',
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/note-rename/public-api.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/note-rename/public-api.ts
index 973c93158b..0d947e0b9f 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/note-rename/public-api.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './note-rename.component';
diff --git a/zeppelin-web-angular/src/app/share/public-api.ts 
b/zeppelin-web-angular/src/app/share/public-api.ts
index b8c2732003..312df06dbd 100644
--- a/zeppelin-web-angular/src/app/share/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/public-api.ts
@@ -10,6 +10,12 @@
  * limitations under the License.
  */
 
+export * from './code-editor';
+export * from './folder-rename';
+export * from './note-create';
+export * from './note-import';
+export * from './note-rename';
 export * from './pipes';
 export * from './resize-handle';
 export * from './share.module';
+export * from './shortcut';
diff --git a/zeppelin-web-angular/src/app/share/share.module.ts 
b/zeppelin-web-angular/src/app/share/share.module.ts
index 25cf7fc2f8..f514a950eb 100644
--- a/zeppelin-web-angular/src/app/share/share.module.ts
+++ b/zeppelin-web-angular/src/app/share/share.module.ts
@@ -37,23 +37,23 @@ import { NzToolTipModule } from 'ng-zorro-antd/tooltip';
 import { NzTreeModule } from 'ng-zorro-antd/tree';
 import { NzUploadModule } from 'ng-zorro-antd/upload';
 
-import { AboutZeppelinComponent } from 
'@zeppelin/share/about-zeppelin/about-zeppelin.component';
-import { CodeEditorModule } from '@zeppelin/share/code-editor';
-import { ExternalLinkDirective } from 
'@zeppelin/share/external-links/external-link.directive';
-import { FolderRenameComponent } from 
'@zeppelin/share/folder-rename/folder-rename.component';
-import { HeaderComponent } from '@zeppelin/share/header/header.component';
-import { MathJaxDirective } from '@zeppelin/share/math-jax/math-jax.directive';
-import { NodeListComponent } from 
'@zeppelin/share/node-list/node-list.component';
-import { NoteCreateComponent } from 
'@zeppelin/share/note-create/note-create.component';
-import { NoteImportComponent } from 
'@zeppelin/share/note-import/note-import.component';
-import { NoteRenameComponent } from 
'@zeppelin/share/note-rename/note-rename.component';
-import { NoteTocComponent } from '@zeppelin/share/note-toc/note-toc.component';
-import { PageHeaderComponent } from 
'@zeppelin/share/page-header/page-header.component';
-import { HumanizeBytesPipe } from '@zeppelin/share/pipes';
-import { RunScriptsDirective } from 
'@zeppelin/share/run-scripts/run-scripts.directive';
-import { ShortcutComponent } from 
'@zeppelin/share/shortcut/shortcut.component';
-import { SpinComponent } from '@zeppelin/share/spin/spin.component';
+import { AboutZeppelinComponent } from 
'./about-zeppelin/about-zeppelin.component';
+import { CodeEditorModule } from './code-editor/code-editor.module';
+import { ExternalLinkDirective } from 
'./external-links/external-link.directive';
+import { FolderRenameComponent } from 
'./folder-rename/folder-rename.component';
+import { HeaderComponent } from './header/header.component';
+import { MathJaxDirective } from './math-jax/math-jax.directive';
+import { NodeListComponent } from './node-list/node-list.component';
+import { NoteCreateComponent } from './note-create/note-create.component';
+import { NoteImportComponent } from './note-import/note-import.component';
+import { NoteRenameComponent } from './note-rename/note-rename.component';
+import { NoteTocComponent } from './note-toc/note-toc.component';
+import { PageHeaderComponent } from './page-header/page-header.component';
+import { HumanizeBytesPipe } from './pipes';
 import { ResizeHandleComponent } from './resize-handle';
+import { RunScriptsDirective } from './run-scripts/run-scripts.directive';
+import { ShortcutComponent } from './shortcut/shortcut.component';
+import { SpinComponent } from './spin/spin.component';
 
 const MODAL_LIST = [
   AboutZeppelinComponent,
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/shortcut/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/shortcut/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/shortcut/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/share/shortcut/public-api.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/share/shortcut/public-api.ts
index 973c93158b..8ea99ef6c7 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/share/shortcut/public-api.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './shortcut.component';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/spell/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/spell/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/spell/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/spell/public-api.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/spell/public-api.ts
index 973c93158b..3cbe3b146f 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/spell/public-api.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './spell-result';
diff --git a/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts 
b/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts
index a5a3689de9..6ffc793b4a 100644
--- a/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts
+++ b/zeppelin-web-angular/src/app/utility/get-keyword-positions.ts
@@ -10,7 +10,7 @@
  * limitations under the License.
  */
 
-import { computeLineStartsMap, getLineAndCharacterFromPosition } from 
'@zeppelin/utility/line-map';
+import { computeLineStartsMap, getLineAndCharacterFromPosition } from 
'./line-map';
 
 export interface KeywordPosition {
   line: number;
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/utility/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/utility/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/utility/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/helium-manager/public-api.ts 
b/zeppelin-web-angular/src/app/utility/public-api.ts
similarity index 76%
copy from zeppelin-web-angular/src/app/helium-manager/public-api.ts
copy to zeppelin-web-angular/src/app/utility/public-api.ts
index 8ba1a21026..ee29d3e983 100644
--- a/zeppelin-web-angular/src/app/helium-manager/public-api.ts
+++ b/zeppelin-web-angular/src/app/utility/public-api.ts
@@ -10,5 +10,8 @@
  * limitations under the License.
  */
 
-export * from './helium-manager.service';
-export * from './helium-manager.module';
+export * from './css-unit-conversion';
+export * from './element';
+export * from './get-keyword-positions';
+export * from './line-map';
+export * from './type-utility';
diff --git a/zeppelin-web-angular/src/app/languages/public-api.ts 
b/zeppelin-web-angular/src/app/visualizations/index.ts
similarity index 91%
copy from zeppelin-web-angular/src/app/languages/public-api.ts
copy to zeppelin-web-angular/src/app/visualizations/index.ts
index 973c93158b..49e4740442 100644
--- a/zeppelin-web-angular/src/app/languages/public-api.ts
+++ b/zeppelin-web-angular/src/app/visualizations/index.ts
@@ -10,5 +10,4 @@
  * limitations under the License.
  */
 
-export * from './scala';
-export * from './load';
+export * from './public-api';
diff --git a/zeppelin-web-angular/src/app/helium-manager/public-api.ts 
b/zeppelin-web-angular/src/app/visualizations/public-api.ts
similarity index 58%
copy from zeppelin-web-angular/src/app/helium-manager/public-api.ts
copy to zeppelin-web-angular/src/app/visualizations/public-api.ts
index 8ba1a21026..4b1b59b043 100644
--- a/zeppelin-web-angular/src/app/helium-manager/public-api.ts
+++ b/zeppelin-web-angular/src/app/visualizations/public-api.ts
@@ -10,5 +10,11 @@
  * limitations under the License.
  */
 
-export * from './helium-manager.service';
-export * from './helium-manager.module';
+export * from './area-chart/area-chart-visualization';
+export * from './bar-chart/bar-chart-visualization';
+export * from './g2.config';
+export * from './line-chart/line-chart-visualization';
+export * from './pie-chart/pie-chart-visualization';
+export * from './scatter-chart/scatter-chart-visualization';
+export * from './table/table-visualization';
+export * from './visualization.module';
diff --git a/zeppelin-web-angular/tslint.json b/zeppelin-web-angular/tslint.json
index f7ab7e7d8a..ea5c703ecb 100644
--- a/zeppelin-web-angular/tslint.json
+++ b/zeppelin-web-angular/tslint.json
@@ -1,4 +1,5 @@
 {
+  "extends": ["tslint-no-circular-imports"],
   "rulesDirectory": ["node_modules/codelyzer", "node_modules/nz-tslint-rules", 
"tslint-rules"],
   "linterOptions": {
     "exclude": ["dist/**", "node/**", "node_modules/**"]

Reply via email to