diff --git a/examples/browser-only/package.json b/examples/browser-only/package.json index c04f8e6bacc72..f42f13a0cb51c 100644 --- a/examples/browser-only/package.json +++ b/examples/browser-only/package.json @@ -22,6 +22,7 @@ "@theia/ai-history": "1.56.0", "@theia/ai-ollama": "1.56.0", "@theia/ai-openai": "1.56.0", + "@theia/ai-scanoss": "1.56.0", "@theia/api-samples": "1.56.0", "@theia/bulk-edit": "1.56.0", "@theia/callhierarchy": "1.56.0", @@ -53,6 +54,7 @@ "@theia/preview": "1.56.0", "@theia/process": "1.56.0", "@theia/property-view": "1.56.0", + "@theia/scanoss": "1.56.0", "@theia/scm": "1.56.0", "@theia/scm-extra": "1.56.0", "@theia/search-in-workspace": "1.56.0", diff --git a/examples/browser-only/tsconfig.json b/examples/browser-only/tsconfig.json index 2c35a886f30d0..f4a8d7c2bf487 100644 --- a/examples/browser-only/tsconfig.json +++ b/examples/browser-only/tsconfig.json @@ -29,6 +29,9 @@ { "path": "../../packages/ai-openai" }, + { + "path": "../../packages/ai-scanoss" + }, { "path": "../../packages/bulk-edit" }, @@ -119,6 +122,9 @@ { "path": "../../packages/property-view" }, + { + "path": "../../packages/scanoss" + }, { "path": "../../packages/scm" }, diff --git a/examples/browser/package.json b/examples/browser/package.json index 3318ea52cefe7..c775d0d017b5a 100644 --- a/examples/browser/package.json +++ b/examples/browser/package.json @@ -33,6 +33,7 @@ "@theia/ai-mcp": "1.56.0", "@theia/ai-ollama": "1.56.0", "@theia/ai-openai": "1.56.0", + "@theia/ai-scanoss": "1.56.0", "@theia/ai-terminal": "1.56.0", "@theia/ai-workspace-agent": "1.56.0", "@theia/api-provider-sample": "1.56.0", @@ -70,6 +71,7 @@ "@theia/process": "1.56.0", "@theia/property-view": "1.56.0", "@theia/remote": "1.56.0", + "@theia/scanoss": "1.56.0", "@theia/scm": "1.56.0", "@theia/scm-extra": "1.56.0", "@theia/search-in-workspace": "1.56.0", diff --git a/examples/browser/tsconfig.json b/examples/browser/tsconfig.json index 776971f687507..5c292172236e8 100644 --- a/examples/browser/tsconfig.json +++ b/examples/browser/tsconfig.json @@ -41,6 +41,9 @@ { "path": "../../packages/ai-openai" }, + { + "path": "../../packages/ai-scanoss" + }, { "path": "../../packages/ai-terminal" }, @@ -146,6 +149,9 @@ { "path": "../../packages/remote" }, + { + "path": "../../packages/scanoss" + }, { "path": "../../packages/scm" }, diff --git a/examples/electron/package.json b/examples/electron/package.json index 84b09461c94a9..374b2b5246650 100644 --- a/examples/electron/package.json +++ b/examples/electron/package.json @@ -35,6 +35,7 @@ "@theia/ai-llamafile": "1.56.0", "@theia/ai-ollama": "1.56.0", "@theia/ai-openai": "1.56.0", + "@theia/ai-scanoss": "1.56.0", "@theia/ai-terminal": "1.56.0", "@theia/ai-workspace-agent": "1.56.0", "@theia/api-provider-sample": "1.56.0", @@ -72,6 +73,7 @@ "@theia/process": "1.56.0", "@theia/property-view": "1.56.0", "@theia/remote": "1.56.0", + "@theia/scanoss": "1.56.0", "@theia/scm": "1.56.0", "@theia/scm-extra": "1.56.0", "@theia/search-in-workspace": "1.56.0", diff --git a/examples/electron/tsconfig.json b/examples/electron/tsconfig.json index f73f79901de16..854b6ffb87e0b 100644 --- a/examples/electron/tsconfig.json +++ b/examples/electron/tsconfig.json @@ -38,6 +38,9 @@ { "path": "../../packages/ai-openai" }, + { + "path": "../../packages/ai-scanoss" + }, { "path": "../../packages/ai-terminal" }, @@ -140,6 +143,9 @@ { "path": "../../packages/remote" }, + { + "path": "../../packages/scanoss" + }, { "path": "../../packages/scm" }, diff --git a/packages/ai-chat-ui/src/browser/ai-chat-ui-frontend-module.ts b/packages/ai-chat-ui/src/browser/ai-chat-ui-frontend-module.ts index b3c7e70f045f2..fce135c107028 100644 --- a/packages/ai-chat-ui/src/browser/ai-chat-ui-frontend-module.ts +++ b/packages/ai-chat-ui/src/browser/ai-chat-ui-frontend-module.ts @@ -19,15 +19,27 @@ import { bindViewContribution, FrontendApplicationContribution, WidgetFactory } import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; import { ContainerModule, interfaces } from '@theia/core/shared/inversify'; import { EditorManager } from '@theia/editor/lib/browser'; -import '../../src/browser/style/index.css'; import { AIChatContribution } from './ai-chat-ui-contribution'; import { AIChatInputWidget } from './chat-input-widget'; import { ChatNodeToolbarActionContribution } from './chat-node-toolbar-action-contribution'; import { ChatResponsePartRenderer } from './chat-response-part-renderer'; -import { CodePartRenderer, CommandPartRenderer, ErrorPartRenderer, HorizontalLayoutPartRenderer, MarkdownPartRenderer, ToolCallPartRenderer } from './chat-response-renderer'; import { - AIEditorManager, AIEditorSelectionResolver, - GitHubSelectionResolver, TextFragmentSelectionResolver, TypeDocSymbolSelectionResolver + CodePartRenderer, + CodePartRendererAction, + CommandPartRenderer, + CopyToClipboardButtonAction, + ErrorPartRenderer, + HorizontalLayoutPartRenderer, + InsertCodeAtCursorButtonAction, + MarkdownPartRenderer, + ToolCallPartRenderer, +} from './chat-response-renderer'; +import { + AIEditorManager, + AIEditorSelectionResolver, + GitHubSelectionResolver, + TextFragmentSelectionResolver, + TypeDocSymbolSelectionResolver, } from './chat-response-renderer/ai-editor-manager'; import { createChatViewTreeWidget } from './chat-tree-view'; import { ChatViewTreeWidget } from './chat-tree-view/chat-view-tree-widget'; @@ -37,6 +49,7 @@ import { ChatViewWidget } from './chat-view-widget'; import { ChatViewWidgetToolbarContribution } from './chat-view-widget-toolbar-contribution'; import { EditorPreviewManager } from '@theia/editor-preview/lib/browser/editor-preview-manager'; import { QuestionPartRenderer } from './chat-response-renderer/question-part-renderer'; +import '../../src/browser/style/index.css'; export default new ContainerModule((bind, _unbind, _isBound, rebind) => { bindViewContribution(bind, AIChatContribution); @@ -72,6 +85,12 @@ export default new ContainerModule((bind, _unbind, _isBound, rebind) => { bind(serviceIdentifier).to(ChatViewMenuContribution).inSingletonScope() ); + bindContributionProvider(bind, CodePartRendererAction); + bind(CopyToClipboardButtonAction).toSelf().inSingletonScope(); + bind(CodePartRendererAction).toService(CopyToClipboardButtonAction); + bind(InsertCodeAtCursorButtonAction).toSelf().inSingletonScope(); + bind(CodePartRendererAction).toService(InsertCodeAtCursorButtonAction); + bind(AIEditorManager).toSelf().inSingletonScope(); rebind(EditorManager).toService(AIEditorManager); rebind(EditorPreviewManager).toService(AIEditorManager); diff --git a/packages/ai-chat-ui/src/browser/chat-response-renderer/code-part-renderer.tsx b/packages/ai-chat-ui/src/browser/chat-response-renderer/code-part-renderer.tsx index b18da161fef2c..080fbcd099050 100644 --- a/packages/ai-chat-ui/src/browser/chat-response-renderer/code-part-renderer.tsx +++ b/packages/ai-chat-ui/src/browser/chat-response-renderer/code-part-renderer.tsx @@ -13,15 +13,14 @@ // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** - import { ChatResponseContent, CodeChatResponseContent, } from '@theia/ai-chat/lib/common'; -import { UntitledResourceResolver, URI } from '@theia/core'; +import { ContributionProvider, UntitledResourceResolver, URI } from '@theia/core'; import { ContextMenuRenderer, TreeNode } from '@theia/core/lib/browser'; import { ClipboardService } from '@theia/core/lib/browser/clipboard-service'; -import { inject, injectable } from '@theia/core/shared/inversify'; +import { inject, injectable, named } from '@theia/core/shared/inversify'; import * as React from '@theia/core/shared/react'; import { ReactNode } from '@theia/core/shared/react'; import { Position } from '@theia/core/shared/vscode-languageserver-protocol'; @@ -33,12 +32,29 @@ import { ChatResponsePartRenderer } from '../chat-response-part-renderer'; import { ChatViewTreeWidget, ResponseNode } from '../chat-tree-view/chat-view-tree-widget'; import { IMouseEvent } from '@theia/monaco-editor-core'; +export const CodePartRendererAction = Symbol('CodePartRendererAction'); +/** + * The CodePartRenderer offers to contribute arbitrary React nodes to the rendered code part. + * Technically anything can be rendered, however it is intended to be used for actions, like + * "Copy to Clipboard" or "Insert at Cursor". + */ +export interface CodePartRendererAction { + render(response: CodeChatResponseContent, parentNode: ResponseNode): ReactNode; + /** + * Determines if the action should be rendered for the given response. + */ + canRender?(response: CodeChatResponseContent, parentNode: ResponseNode): boolean; + /** + * The priority determines the order in which the actions are rendered. + * The default priorities are 10 and 20. + */ + priority: number; +} + @injectable() export class CodePartRenderer implements ChatResponsePartRenderer { - @inject(ClipboardService) - protected readonly clipboardService: ClipboardService; @inject(EditorManager) protected readonly editorManager: EditorManager; @inject(UntitledResourceResolver) @@ -49,6 +65,8 @@ export class CodePartRenderer protected readonly languageService: MonacoLanguages; @inject(ContextMenuRenderer) protected readonly contextMenuRenderer: ContextMenuRenderer; + @inject(ContributionProvider) @named(CodePartRendererAction) + protected readonly codePartRendererActions: ContributionProvider; canHandle(response: ChatResponseContent): number { if (CodeChatResponseContent.is(response)) { @@ -59,14 +77,15 @@ export class CodePartRenderer render(response: CodeChatResponseContent, parentNode: ResponseNode): ReactNode { const language = response.language ? this.languageService.getExtension(response.language) : undefined; - return (
{this.renderTitle(response)}
-
- - +
+ {this.codePartRendererActions.getContributions() + .filter(action => action.canRender ? action.canRender(response, parentNode) : true) + .sort((a, b) => a.priority - b.priority) + .map(action => action.render(response, parentNode))}
@@ -123,6 +142,16 @@ export class CodePartRenderer } } +@injectable() +export class CopyToClipboardButtonAction implements CodePartRendererAction { + @inject(ClipboardService) + protected readonly clipboardService: ClipboardService; + priority = 10; + render(response: CodeChatResponseContent): ReactNode { + return ; + } +} + const CopyToClipboardButton = (props: { code: string, clipboardService: ClipboardService }) => { const { code, clipboardService } = props; const copyCodeToClipboard = React.useCallback(() => { @@ -131,6 +160,16 @@ const CopyToClipboardButton = (props: { code: string, clipboardService: Clipboar return
; }; +@injectable() +export class InsertCodeAtCursorButtonAction implements CodePartRendererAction { + @inject(EditorManager) + protected readonly editorManager: EditorManager; + priority = 20; + render(response: CodeChatResponseContent): ReactNode { + return ; + } +} + const InsertCodeAtCursorButton = (props: { code: string, editorManager: EditorManager }) => { const { code, editorManager } = props; const insertCode = React.useCallback(() => { diff --git a/packages/ai-chat/src/common/chat-model.ts b/packages/ai-chat/src/common/chat-model.ts index 9c6cd66af14b4..22b8e8b0d714d 100644 --- a/packages/ai-chat/src/common/chat-model.ts +++ b/packages/ai-chat/src/common/chat-model.ts @@ -321,18 +321,59 @@ export interface ChatResponse { asString(): string; } +/** + * The ChatResponseModel wraps the actual ChatResponse with additional information like the current state, progress messages, a unique id etc. + */ export interface ChatResponseModel { + /** + * Use this to be notified for any change in the response model + */ readonly onDidChange: Event; + /** + * The unique identifier of the response model + */ readonly id: string; + /** + * The unique identifier of the request model this response is associated with + */ readonly requestId: string; + /** + * In case there are progress messages, then they will be stored here + */ readonly progressMessages: ChatProgressMessage[]; + /** + * The actual response content + */ readonly response: ChatResponse; + /** + * Indicates whether this response is complete. No further changes are expected if 'true'. + */ readonly isComplete: boolean; + /** + * Indicates whether this response is canceled. No further changes are expected if 'true'. + */ readonly isCanceled: boolean; + /** + * Some agents might need to wait for user input to continue. This flag indicates that. + */ readonly isWaitingForInput: boolean; + /** + * Indicates whether an error occurred when processing the response. No further changes are expected if 'true'. + */ readonly isError: boolean; + /** + * The agent who produced the response content, if there is one. + */ readonly agentId?: string + /** + * An optional error object that caused the response to be in an error state. + */ readonly errorObject?: Error; + /** + * Some functionality might want to store some data associated with the response. + * This can be used to store and retrieve such data. + */ + readonly data: { [key: string]: unknown }; } /********************** @@ -750,6 +791,8 @@ class ChatResponseModelImpl implements ChatResponseModel { protected readonly _onDidChangeEmitter = new Emitter(); onDidChange: Event = this._onDidChangeEmitter.event; + data = {}; + protected _id: string; protected _requestId: string; protected _progressMessages: ChatProgressMessage[]; diff --git a/packages/ai-scanoss/.eslintrc.js b/packages/ai-scanoss/.eslintrc.js new file mode 100644 index 0000000000000..13089943582b6 --- /dev/null +++ b/packages/ai-scanoss/.eslintrc.js @@ -0,0 +1,10 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + extends: [ + '../../configs/build.eslintrc.json' + ], + parserOptions: { + tsconfigRootDir: __dirname, + project: 'tsconfig.json' + } +}; diff --git a/packages/ai-scanoss/README.md b/packages/ai-scanoss/README.md new file mode 100644 index 0000000000000..8cbbff7e0f349 --- /dev/null +++ b/packages/ai-scanoss/README.md @@ -0,0 +1,34 @@ +
+ +
+ +theia-ext-logo + +

ECLIPSE THEIA - SCAN OSS AI EXTENSION

+ +
+ +
+ +## Description + +Integrates SCANOSS content scanning into the Chat View. +Whenever a code listing is rendered, a scan action is offered to the user. + +Via the preferences the user can switch between manual and automatic scanning. + +## Additional Information + +- [Theia - GitHub](https://github.com/eclipse-theia/theia) +- [Theia - Website](https://theia-ide.org/) +- [SCAN OSS Website](https://www.scanoss.com/) + +## License + +- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/) +- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp) + +## Trademark + +"Theia" is a trademark of the Eclipse Foundation + diff --git a/packages/ai-scanoss/package.json b/packages/ai-scanoss/package.json new file mode 100644 index 0000000000000..72d4dcc38250d --- /dev/null +++ b/packages/ai-scanoss/package.json @@ -0,0 +1,51 @@ +{ + "name": "@theia/ai-scanoss", + "version": "1.56.0", + "description": "Theia - SCANOSS AI Integration", + "dependencies": { + "@theia/core": "1.56.0", + "@theia/ai-core": "1.56.0", + "@theia/ai-chat": "1.56.0", + "@theia/ai-chat-ui": "1.56.0", + "@theia/scanoss": "1.56.0" + }, + "publishConfig": { + "access": "public" + }, + "theiaExtensions": [ + { + "frontend": "lib/browser/ai-scanoss-frontend-module" + } + ], + "keywords": [ + "theia-extension" + ], + "license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0", + "repository": { + "type": "git", + "url": "https://github.com/eclipse-theia/theia.git" + }, + "bugs": { + "url": "https://github.com/eclipse-theia/theia/issues" + }, + "homepage": "https://github.com/eclipse-theia/theia", + "files": [ + "lib", + "src" + ], + "main": "lib/common", + "scripts": { + "build": "theiaext build", + "clean": "theiaext clean", + "compile": "theiaext compile", + "lint": "theiaext lint", + "test": "theiaext test", + "watch": "theiaext watch" + }, + "devDependencies": { + "@theia/ext-scripts": "1.56.0" + }, + "nyc": { + "extends": "../../configs/nyc.json" + } +} diff --git a/packages/ai-scanoss/src/browser/ai-scanoss-code-scan-action.tsx b/packages/ai-scanoss/src/browser/ai-scanoss-code-scan-action.tsx new file mode 100644 index 0000000000000..d62d9f4d423d8 --- /dev/null +++ b/packages/ai-scanoss/src/browser/ai-scanoss-code-scan-action.tsx @@ -0,0 +1,235 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// *** +import { inject, injectable } from '@theia/core/shared/inversify'; +import { CodeChatResponseContent } from '@theia/ai-chat'; +import { CodePartRendererAction } from '@theia/ai-chat-ui/lib/browser/chat-response-renderer'; +import { + ScanOSSResult, + ScanOSSResultMatch, + ScanOSSService, +} from '@theia/scanoss'; +import { Dialog, PreferenceService } from '@theia/core/lib/browser'; +import { ReactNode } from '@theia/core/shared/react'; +import { ResponseNode } from '@theia/ai-chat-ui/lib/browser/chat-tree-view'; +import * as React from '@theia/core/shared/react'; +import { ReactDialog } from '@theia/core/lib/browser/dialogs/react-dialog'; +import { SCAN_OSS_API_KEY_PREF } from '@theia/scanoss/lib/browser/scanoss-preferences'; +import { SCANOSS_MODE_PREF } from './ai-scanoss-preferences'; + +// cached map of scanOSS results. +// 'false' is stored when not automatic check is off and it was not (yet) requested deliberately. +type ScanOSSResults = Map; +interface HasScanOSSResults { + scanOSSResults: ScanOSSResults; + [key: string]: unknown; +} +function hasScanOSSResults(data: { + [key: string]: unknown; +}): data is HasScanOSSResults { + return 'scanOSSResults' in data && data.scanOSSResults instanceof Map; +} + +@injectable() +export class ScanOSSScanButtonAction implements CodePartRendererAction { + @inject(ScanOSSService) + protected readonly scanService: ScanOSSService; + @inject(PreferenceService) + protected readonly preferenceService: PreferenceService; + + priority = 30; + + canRender(response: CodeChatResponseContent, parentNode: ResponseNode): boolean { + if (!hasScanOSSResults(parentNode.response.data)) { + parentNode.response.data.scanOSSResults = new Map< + string, + ScanOSSResult + >(); + } + const results = parentNode.response.data + .scanOSSResults as ScanOSSResults; + const scanOSSMode = this.preferenceService.get(SCANOSS_MODE_PREF, 'off'); + // we mark the code for manual scanning in case it was not handled yet and the mode is manual or off. + // this prevents a possibly unexpected automatic scan of "old" snippets if automatic scan is later turned on. + if (results.get(response.code) === undefined && (scanOSSMode === 'off' || scanOSSMode === 'manual')) { + results.set(response.code, false); + } + return scanOSSMode !== 'off'; + } + + render( + response: CodeChatResponseContent, + parentNode: ResponseNode + ): ReactNode { + const scanOSSResults = parentNode.response.data + .scanOSSResults as ScanOSSResults; + + return ( + + ); + } +} + +const ScanOSSIntegration = React.memo((props: { + code: string; + scanService: ScanOSSService; + scanOSSResults: ScanOSSResults; + preferenceService: PreferenceService; +}) => { + const [automaticCheck] = React.useState(() => + props.preferenceService.get(SCANOSS_MODE_PREF, 'off') === 'automatic' + ); + const [scanOSSResult, setScanOSSResult] = React.useState< + ScanOSSResult | 'pending' | undefined | false + >(props.scanOSSResults.get(props.code)); + const scanCode = React.useCallback(async () => { + setScanOSSResult('pending'); + const result = await props.scanService.scanContent(props.code, props.preferenceService.get(SCAN_OSS_API_KEY_PREF, undefined)); + setScanOSSResult(result); + props.scanOSSResults.set(props.code, result); + return result; + }, [props.code, props.scanService]); + + React.useEffect(() => { + if (scanOSSResult === undefined) { + if (automaticCheck) { + scanCode(); + } else { + // sanity fallback. This codepath should already be handled via "canRender" + props.scanOSSResults.set(props.code, false); + } + } + }, []); + const scanOSSClicked = React.useCallback(async () => { + let scanResult = scanOSSResult; + if (scanResult === 'pending') { + return; + } + if (!scanResult || scanResult.type === 'error') { + scanResult = await scanCode(); + } + if (scanResult && scanResult.type === 'match') { + const dialog = new ScanOSSDialog(scanResult); + dialog.open(); + } + }, [scanOSSResult]); + let title = 'SCANOSS - Perform scan'; + if (scanOSSResult) { + if (scanOSSResult === 'pending') { + title = 'SCANOSS - Performing scan...'; + } else if (scanOSSResult.type === 'error') { + title = `SCANOSS - Error - ${scanOSSResult.message}`; + } else if (scanOSSResult.type === 'match') { + title = `SCANOSS - Found ${scanOSSResult.matched} match`; + } else if (scanOSSResult.type === 'clean') { + title = 'SCANOSS - No match'; + } + } + return ( + <> +
+
+ {scanOSSResult && scanOSSResult !== 'pending' && ( + + {scanOSSResult.type === 'clean' && } + {scanOSSResult.type === 'match' && } + {scanOSSResult.type === 'error' && } + + )} +
+ + ); +}); + +export class ScanOSSDialog extends ReactDialog { + protected readonly okButton: HTMLButtonElement; + + constructor(protected result: ScanOSSResultMatch) { + super({ + title: 'SCANOSS Results', + }); + this.appendAcceptButton(Dialog.OK); + this.update(); + } + + protected render(): React.ReactNode { + return ( +
+ {this.renderHeader()} + {this.renderSummary()} + {this.renderContent()} +
+ ); + } + + protected renderHeader(): React.ReactNode { + return ( +
+
+
+

SCANOSS

+
+
+ ); + } + + protected renderSummary(): React.ReactNode { + return ( +
+

Summary

+
+ Found a {this.result.matched} match in{' '} + + {this.result.url} + +
+
+ ); + } + + protected renderContent(): React.ReactNode { + return ( +
+

Details

+
+                    {
+                        // eslint-disable-next-line no-null/no-null
+                        JSON.stringify(this.result.raw, null, 2)
+                    }
+                
+
+ ); + } + + get value(): undefined { + return undefined; + } +} diff --git a/packages/ai-scanoss/src/browser/ai-scanoss-frontend-module.ts b/packages/ai-scanoss/src/browser/ai-scanoss-frontend-module.ts new file mode 100644 index 0000000000000..f6f3b2ef0b34e --- /dev/null +++ b/packages/ai-scanoss/src/browser/ai-scanoss-frontend-module.ts @@ -0,0 +1,28 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import { ContainerModule } from '@theia/core/shared/inversify'; +import { AIScanOSSPreferencesSchema } from './ai-scanoss-preferences'; +import { PreferenceContribution } from '@theia/core/lib/browser'; +import { ScanOSSScanButtonAction } from './ai-scanoss-code-scan-action'; +import { CodePartRendererAction } from '@theia/ai-chat-ui/lib/browser/chat-response-renderer'; +import '../../src/browser/style/index.css'; + +export default new ContainerModule(bind => { + bind(PreferenceContribution).toConstantValue({ schema: AIScanOSSPreferencesSchema }); + bind(ScanOSSScanButtonAction).toSelf().inSingletonScope(); + bind(CodePartRendererAction).toService(ScanOSSScanButtonAction); +}); diff --git a/packages/ai-scanoss/src/browser/ai-scanoss-preferences.ts b/packages/ai-scanoss/src/browser/ai-scanoss-preferences.ts new file mode 100644 index 0000000000000..def42c0f2350a --- /dev/null +++ b/packages/ai-scanoss/src/browser/ai-scanoss-preferences.ts @@ -0,0 +1,39 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import { PreferenceSchema } from '@theia/core/lib/browser/preferences'; +import { AI_CORE_PREFERENCES_TITLE } from '@theia/ai-core/lib/browser/ai-core-preferences'; + +export const SCANOSS_MODE_PREF = 'ai-features.SCANOSS.mode'; + +export const AIScanOSSPreferencesSchema: PreferenceSchema = { + type: 'object', + properties: { + [SCANOSS_MODE_PREF]: { + type: 'string', + enum: ['off', 'manual', 'automatic'], + markdownEnumDescriptions: [ + 'Feature is turned off completely.', + 'User can manually trigger the scan by clicking the SCANOSS item in the chat view.', + 'Enable automatic scan of code snippets in chat views.' + ], + markdownDescription: 'Configure the SCANOSS feature for analyzing code snippets in chat views. This will send a hash of suggested code snippets to the SCANOSS\n\ + service hosted by the [Software Transparency foundation](https://www.softwaretransparency.org/osskb) for analysis.', + default: 'off', + title: AI_CORE_PREFERENCES_TITLE + } + } +}; diff --git a/packages/ai-scanoss/src/browser/style/index.css b/packages/ai-scanoss/src/browser/style/index.css new file mode 100644 index 0000000000000..44b301361e97c --- /dev/null +++ b/packages/ai-scanoss/src/browser/style/index.css @@ -0,0 +1,132 @@ +.scanoss-logo { + background-image: url("scanoss_logo_dark_theme.svg"); + background-repeat: no-repeat; + background-position: center; +} + +.vs-light .scanoss-logo, +.theia-light .scanoss-logo, +.light-theia .scanoss-logo { + background-image: url("scanoss_logo_light_theme.svg"); +} + +/* We need a more detailed selector to override the default button style */ +.theia-CodePartRenderer-actions .scanoss-logo { + background-size: 82% auto; /* scale the image to be a bit smaller than the button because the codicon icons are also smaller */ + transition: filter 0.3s; + display: inline-block; +} + +.scanoss-logo.requesting { + animation: pulse 1s infinite ease-in-out; +} + +/* Use a rounded background when not hovered */ +.theia-CodePartRenderer-actions .scanoss-logo:not(:hover) { + border-radius: 50%; +} + +.scanoss-logo.clean { + background-color: rgba(46, 125, 50, 0.3); /* translucent green */ +} + +.scanoss-logo.match { + background-color: rgba(249, 215, 116, 0.3); /* translucent yellow */ +} + +.scanoss-logo.error { + background-color: rgba(210, 72, 72, 0.3); /* translucent red */ +} + +.icon-container { + position: relative; + display: inline-block; + width: 16px; + height: 16px; +} + +/* The placeholder is used to align with the remaining actions, however it should not be visible*/ +.scanoss-logo .placeholder { + visibility: hidden; +} + +/* The status icon is used to display the result of the scan on the top right */ +.scanoss-logo .status-icon { + position: absolute; + transform: translate(-4px, -5px); +} + +.scanoss-logo.clean .status-icon { + color: green; +} +.scanoss-logo.match .status-icon { + color: yellow; + text-shadow: 0 0 3px rgba(0,0,0,0.9); +} +.scanoss-logo.error .status-icon { + color: red; + text-shadow: 0 0 3px currentColor +} + +/* Disable the button when it's in the clean state */ +.theia-CodePartRenderer-actions .scanoss-logo.clean{ + pointer-events: none; + cursor: default; +} + +.scanoss-dialog-container .scanoss-header { + display: flex; + flex-direction: column; + align-items: center; + margin-bottom: 20px; +} + +.scanoss-dialog-container .scanoss-logo-container { + display: flex; + flex-direction: row; + align-items: center; + gap: 10px; +} + +.scanoss-dialog-container .scanoss-logo { + width: 40px; + height: 40px; + background-size: contain; +} + +.scanoss-dialog-container .scanoss-logo-container h2 { + font-size: 1.8em; + margin: 0; +} + +.scanoss-dialog-container .scanoss-summary { + padding: 15px; + border-radius: 4px; + margin-bottom: 20px; +} + +.scanoss-dialog-container .scanoss-summary h3 { + margin-top: 0; + font-size: 1.4em; + margin-bottom: 10px; +} + +.scanoss-dialog-container .scanoss-details { + padding: 15px; + border-radius: 4px; + border: 1px solid var(--theia-sideBarSectionHeader-border); +} + +.scanoss-dialog-container .scanoss-details h4 { + margin-top: 0; + font-size: 1.2em; + margin-bottom: 10px; +} + +.scanoss-dialog-container .scanoss-details pre { + background: var(--theia-editor-background); + padding: 10px; + border-radius: 4px; + overflow: auto; + font-size: 0.9em; +} diff --git a/packages/ai-scanoss/src/browser/style/scanoss_logo_dark_theme.svg b/packages/ai-scanoss/src/browser/style/scanoss_logo_dark_theme.svg new file mode 100644 index 0000000000000..63feca8acbf8e --- /dev/null +++ b/packages/ai-scanoss/src/browser/style/scanoss_logo_dark_theme.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/ai-scanoss/src/browser/style/scanoss_logo_light_theme.svg b/packages/ai-scanoss/src/browser/style/scanoss_logo_light_theme.svg new file mode 100644 index 0000000000000..9a9893fb654e4 --- /dev/null +++ b/packages/ai-scanoss/src/browser/style/scanoss_logo_light_theme.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/packages/ai-scanoss/src/package.spec.ts b/packages/ai-scanoss/src/package.spec.ts new file mode 100644 index 0000000000000..084f1c24121bb --- /dev/null +++ b/packages/ai-scanoss/src/package.spec.ts @@ -0,0 +1,28 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +/* note: this bogus test file is required so that + we are able to run mocha unit tests on this + package, without having any actual unit tests in it. + This way a coverage report will be generated, + showing 0% coverage, instead of no report. + This file can be removed once we have real unit + tests in place. */ + +describe('ai-scanoss package', () => { + + it('support code coverage statistics', () => true); +}); diff --git a/packages/ai-scanoss/tsconfig.json b/packages/ai-scanoss/tsconfig.json new file mode 100644 index 0000000000000..8f9b281532633 --- /dev/null +++ b/packages/ai-scanoss/tsconfig.json @@ -0,0 +1,28 @@ +{ + "extends": "../../configs/base.tsconfig", + "compilerOptions": { + "composite": true, + "rootDir": "src", + "outDir": "lib" + }, + "include": [ + "src" + ], + "references": [ + { + "path": "../ai-chat" + }, + { + "path": "../ai-chat-ui" + }, + { + "path": "../ai-core" + }, + { + "path": "../core" + }, + { + "path": "../scanoss" + } + ] +} diff --git a/packages/git/src/electron-browser/prompt/git-quick-open-prompt.ts b/packages/git/src/electron-browser/prompt/git-quick-open-prompt.ts index 75a3c23cac1d3..7b7e0ba1b98ba 100644 --- a/packages/git/src/electron-browser/prompt/git-quick-open-prompt.ts +++ b/packages/git/src/electron-browser/prompt/git-quick-open-prompt.ts @@ -16,7 +16,7 @@ import { inject, injectable, optional } from '@theia/core/shared/inversify'; import { QuickInputService } from '@theia/core/lib/browser'; -import * as PQueue from 'p-queue'; +import PQueue from 'p-queue'; import { GitPrompt } from '../../common/git-prompt'; @injectable() diff --git a/packages/git/tsconfig.json b/packages/git/tsconfig.json index 7fac7b0037c1a..fe22e0b245070 100644 --- a/packages/git/tsconfig.json +++ b/packages/git/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "composite": true, "rootDir": "src", - "outDir": "lib" + "outDir": "lib", + "esModuleInterop": true }, "include": [ "src" diff --git a/packages/memory-inspector/src/browser/diff-widget/memory-diff-select-widget.tsx b/packages/memory-inspector/src/browser/diff-widget/memory-diff-select-widget.tsx index 68e4302dae4f4..c84c68e197b56 100644 --- a/packages/memory-inspector/src/browser/diff-widget/memory-diff-select-widget.tsx +++ b/packages/memory-inspector/src/browser/diff-widget/memory-diff-select-widget.tsx @@ -17,7 +17,7 @@ import { Key, KeyCode, Message, ReactWidget } from '@theia/core/lib/browser'; import { inject, injectable, postConstruct } from '@theia/core/shared/inversify'; import * as React from '@theia/core/shared/react'; -import * as Long from 'long'; +import Long from 'long'; import { MemoryWidget } from '../memory-widget/memory-widget'; import { RegisterWidget } from '../register-widget/register-widget-types'; import { MWSelect } from '../utils/memory-widget-components'; diff --git a/packages/memory-inspector/src/browser/diff-widget/memory-diff-table-widget.tsx b/packages/memory-inspector/src/browser/diff-widget/memory-diff-table-widget.tsx index bd190ed17ec26..7a11792ce0f2e 100644 --- a/packages/memory-inspector/src/browser/diff-widget/memory-diff-table-widget.tsx +++ b/packages/memory-inspector/src/browser/diff-widget/memory-diff-table-widget.tsx @@ -16,7 +16,7 @@ import { inject, injectable } from '@theia/core/shared/inversify'; import * as React from '@theia/core/shared/react'; -import * as Long from 'long'; +import Long from 'long'; import { MemoryTable, MemoryTableWidget } from '../memory-widget/memory-table-widget'; import { MemoryWidget } from '../memory-widget/memory-widget'; import { EasilyMappedObject } from '../utils/memory-hover-renderer'; diff --git a/packages/memory-inspector/src/browser/editable-widget/memory-editable-table-widget.tsx b/packages/memory-inspector/src/browser/editable-widget/memory-editable-table-widget.tsx index ef92a307733c2..6b4e3284a28f1 100644 --- a/packages/memory-inspector/src/browser/editable-widget/memory-editable-table-widget.tsx +++ b/packages/memory-inspector/src/browser/editable-widget/memory-editable-table-widget.tsx @@ -18,7 +18,7 @@ import { Key, KeyCode } from '@theia/core/lib/browser'; import { Deferred } from '@theia/core/lib/common/promise-util'; import { injectable } from '@theia/core/shared/inversify'; import * as React from '@theia/core/shared/react'; -import * as Long from 'long'; +import Long from 'long'; import { DebugProtocol } from '@vscode/debugprotocol'; import { hexStrToUnsignedLong } from '../../common/util'; import { MemoryOptionsWidget } from '../memory-widget/memory-options-widget'; diff --git a/packages/memory-inspector/src/browser/memory-inspector-frontend-contribution.ts b/packages/memory-inspector/src/browser/memory-inspector-frontend-contribution.ts index c084dcfd0cc38..b3a775b99613d 100644 --- a/packages/memory-inspector/src/browser/memory-inspector-frontend-contribution.ts +++ b/packages/memory-inspector/src/browser/memory-inspector-frontend-contribution.ts @@ -25,7 +25,6 @@ import { inject, injectable, postConstruct } from '@theia/core/shared/inversify' import { DebugScope, DebugVariable } from '@theia/debug/lib/browser/console/debug-console-items'; import { DebugFrontendApplicationContribution } from '@theia/debug/lib/browser/debug-frontend-application-contribution'; import { DebugVariablesWidget } from '@theia/debug/lib/browser/view/debug-variables-widget'; -import * as Long from 'long'; import { MemoryEditableTableWidget } from './editable-widget/memory-editable-table-widget'; import { MemoryProviderService } from './memory-provider/memory-provider-service'; import { MemoryTableWidget } from './memory-widget/memory-table-widget'; @@ -41,6 +40,7 @@ import { VariableRange } from './utils/memory-widget-variable-utils'; import { MemoryDockPanel } from './wrapper-widgets/memory-dock-panel'; import { MemoryLayoutWidget } from './wrapper-widgets/memory-layout-widget'; import { nls } from '@theia/core/lib/common/nls'; +import Long from 'long'; const ONE_HALF_OPACITY = 0.5; diff --git a/packages/memory-inspector/src/browser/memory-provider/memory-provider.ts b/packages/memory-inspector/src/browser/memory-provider/memory-provider.ts index 32d215f9e6ac2..0be87a5ef5ef3 100644 --- a/packages/memory-inspector/src/browser/memory-provider/memory-provider.ts +++ b/packages/memory-inspector/src/browser/memory-provider/memory-provider.ts @@ -20,7 +20,7 @@ import { DebugSession } from '@theia/debug/lib/browser/debug-session'; import { DebugProtocol } from '@vscode/debugprotocol'; import { Interfaces } from '../utils/memory-widget-utils'; import { VariableRange } from '../utils/memory-widget-variable-utils'; -import Long = require('long'); +import Long from 'long'; export const MemoryProvider = Symbol('MemoryProvider'); /** diff --git a/packages/memory-inspector/src/browser/memory-widget/memory-options-widget.tsx b/packages/memory-inspector/src/browser/memory-widget/memory-options-widget.tsx index 9e95fcc03f32e..ba5f7817cc308 100644 --- a/packages/memory-inspector/src/browser/memory-widget/memory-options-widget.tsx +++ b/packages/memory-inspector/src/browser/memory-widget/memory-options-widget.tsx @@ -21,7 +21,7 @@ import { inject, injectable, postConstruct } from '@theia/core/shared/inversify' import * as React from '@theia/core/shared/react'; import { DebugSession, DebugState } from '@theia/debug/lib/browser/debug-session'; import { DebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager'; -import * as Long from 'long'; +import Long from 'long'; import { MemoryProviderService } from '../memory-provider/memory-provider-service'; import { Recents } from '../utils/memory-recents'; import { MWInput, MWInputWithSelect, MWSelect } from '../utils/memory-widget-components'; diff --git a/packages/memory-inspector/src/browser/utils/memory-widget-utils.tsx b/packages/memory-inspector/src/browser/utils/memory-widget-utils.tsx index 3b88978099884..6d9ac96207930 100644 --- a/packages/memory-inspector/src/browser/utils/memory-widget-utils.tsx +++ b/packages/memory-inspector/src/browser/utils/memory-widget-utils.tsx @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 ********************************************************************************/ -import * as Long from 'long'; +import Long from 'long'; import { VariableRange, VariableDecoration } from './memory-widget-variable-utils'; export namespace Constants { diff --git a/packages/memory-inspector/src/browser/utils/memory-widget-variable-utils.ts b/packages/memory-inspector/src/browser/utils/memory-widget-variable-utils.ts index 95dfe3049ce14..dc63e00b19618 100644 --- a/packages/memory-inspector/src/browser/utils/memory-widget-variable-utils.ts +++ b/packages/memory-inspector/src/browser/utils/memory-widget-variable-utils.ts @@ -16,7 +16,7 @@ import { DebugScope, DebugVariable } from '@theia/debug/lib/browser/console/debug-console-items'; import { DebugSession } from '@theia/debug/lib/browser/debug-session'; -import * as Long from 'long'; +import Long from 'long'; export interface VariableRange { name: string; diff --git a/packages/memory-inspector/src/common/util.ts b/packages/memory-inspector/src/common/util.ts index c7ff377128f45..f30c8e0d0e8ba 100644 --- a/packages/memory-inspector/src/common/util.ts +++ b/packages/memory-inspector/src/common/util.ts @@ -14,7 +14,7 @@ * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 ********************************************************************************/ -import * as Long from 'long'; +import Long from 'long'; /** * Parse `hexStr` as an hexadecimal string (with or without the leading 0x) diff --git a/packages/memory-inspector/src/common/utils.spec.ts b/packages/memory-inspector/src/common/utils.spec.ts index 410e05389f338..bc17699233032 100644 --- a/packages/memory-inspector/src/common/utils.spec.ts +++ b/packages/memory-inspector/src/common/utils.spec.ts @@ -16,7 +16,7 @@ import { hexStrToUnsignedLong } from './util'; import { expect } from 'chai'; -import * as Long from 'long'; +import Long from 'long'; describe('utils', function (): void { it('#hexStrToUnsignedLong', function (): void { diff --git a/packages/memory-inspector/tsconfig.json b/packages/memory-inspector/tsconfig.json index 10c4c8f6841d9..65105aa7dce33 100644 --- a/packages/memory-inspector/tsconfig.json +++ b/packages/memory-inspector/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "composite": true, "rootDir": "src", - "outDir": "lib" + "outDir": "lib", + "esModuleInterop": true }, "include": [ "src" diff --git a/packages/output/src/browser/output-channel.ts b/packages/output/src/browser/output-channel.ts index 2097d8c860cb1..b9760d3e08725 100644 --- a/packages/output/src/browser/output-channel.ts +++ b/packages/output/src/browser/output-channel.ts @@ -14,7 +14,7 @@ // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** -import * as PQueue from 'p-queue'; +import PQueue from 'p-queue'; import { injectable, inject } from '@theia/core/shared/inversify'; import URI from '@theia/core/lib/common/uri'; import { Deferred } from '@theia/core/lib/common/promise-util'; diff --git a/packages/output/tsconfig.json b/packages/output/tsconfig.json index d724ea1f75211..d83aab01a9899 100644 --- a/packages/output/tsconfig.json +++ b/packages/output/tsconfig.json @@ -3,7 +3,8 @@ "compilerOptions": { "composite": true, "rootDir": "src", - "outDir": "lib" + "outDir": "lib", + "esModuleInterop": true }, "include": [ "src" diff --git a/packages/scanoss/.eslintrc.js b/packages/scanoss/.eslintrc.js new file mode 100644 index 0000000000000..13089943582b6 --- /dev/null +++ b/packages/scanoss/.eslintrc.js @@ -0,0 +1,10 @@ +/** @type {import('eslint').Linter.Config} */ +module.exports = { + extends: [ + '../../configs/build.eslintrc.json' + ], + parserOptions: { + tsconfigRootDir: __dirname, + project: 'tsconfig.json' + } +}; diff --git a/packages/scanoss/README.md b/packages/scanoss/README.md new file mode 100644 index 0000000000000..4e2f919a4b18f --- /dev/null +++ b/packages/scanoss/README.md @@ -0,0 +1,33 @@ +
+ +
+ +theia-ext-logo + +

ECLIPSE THEIA - SCAN OSS EXTENSION

+ +
+ +
+ +## Description + +Offers a `ScanOSSService` on the backend and frontend for scanning code snippets. + +If needed, an API key can be handed over via preference or environment variable (`SCANOSS_API_KEY`). + +## Additional Information + +- [Theia - GitHub](https://github.com/eclipse-theia/theia) +- [Theia - Website](https://theia-ide.org/) +- [SCAN OSS Website](https://www.scanoss.com/) + +## License + +- [Eclipse Public License 2.0](http://www.eclipse.org/legal/epl-2.0/) +- [一 (Secondary) GNU General Public License, version 2 with the GNU Classpath Exception](https://projects.eclipse.org/license/secondary-gpl-2.0-cp) + +## Trademark + +"Theia" is a trademark of the Eclipse Foundation + diff --git a/packages/scanoss/package.json b/packages/scanoss/package.json new file mode 100644 index 0000000000000..a1f47fdf39649 --- /dev/null +++ b/packages/scanoss/package.json @@ -0,0 +1,49 @@ +{ + "name": "@theia/scanoss", + "version": "1.56.0", + "description": "Theia - SCANOSS Integration", + "dependencies": { + "@theia/core": "1.56.0", + "scanoss": "^0.15.2" + }, + "publishConfig": { + "access": "public" + }, + "theiaExtensions": [ + { + "frontend": "lib/browser/scanoss-frontend-module", + "backend": "lib/node/scanoss-backend-module" + } + ], + "keywords": [ + "theia-extension" + ], + "license": "EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0", + "repository": { + "type": "git", + "url": "https://github.com/eclipse-theia/theia.git" + }, + "bugs": { + "url": "https://github.com/eclipse-theia/theia/issues" + }, + "homepage": "https://github.com/eclipse-theia/theia", + "files": [ + "lib", + "src" + ], + "main": "lib/common", + "scripts": { + "build": "theiaext build", + "clean": "theiaext clean", + "compile": "theiaext compile", + "lint": "theiaext lint", + "test": "theiaext test", + "watch": "theiaext watch" + }, + "devDependencies": { + "@theia/ext-scripts": "1.56.0" + }, + "nyc": { + "extends": "../../configs/nyc.json" + } +} diff --git a/packages/scanoss/src/browser/scanoss-frontend-module.ts b/packages/scanoss/src/browser/scanoss-frontend-module.ts new file mode 100644 index 0000000000000..b902cd5ec19e8 --- /dev/null +++ b/packages/scanoss/src/browser/scanoss-frontend-module.ts @@ -0,0 +1,28 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import { ContainerModule } from '@theia/core/shared/inversify'; +import { ScanOSSPreferencesSchema } from './scanoss-preferences'; +import { PreferenceContribution, RemoteConnectionProvider, ServiceConnectionProvider } from '@theia/core/lib/browser'; +import { SCANOSS_SERVICE_PATH, ScanOSSService } from '../common'; + +export default new ContainerModule(bind => { + bind(PreferenceContribution).toConstantValue({ schema: ScanOSSPreferencesSchema }); + bind(ScanOSSService).toDynamicValue(ctx => { + const provider = ctx.container.get(RemoteConnectionProvider); + return provider.createProxy(SCANOSS_SERVICE_PATH); + }).inSingletonScope(); +}); diff --git a/packages/scanoss/src/browser/scanoss-preferences.ts b/packages/scanoss/src/browser/scanoss-preferences.ts new file mode 100644 index 0000000000000..8625aa32e10cc --- /dev/null +++ b/packages/scanoss/src/browser/scanoss-preferences.ts @@ -0,0 +1,31 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import { PreferenceSchema } from '@theia/core/lib/browser/preferences'; + +export const SCAN_OSS_API_KEY_PREF = 'SCANOSS.apiKey'; + +export const ScanOSSPreferencesSchema: PreferenceSchema = { + type: 'object', + properties: { + [SCAN_OSS_API_KEY_PREF]: { + type: 'string', + markdownDescription: 'Enter an API Key of your SCANOSS Account. **Please note:** By using this preference the key will be stored in clear text\ + on the machine running Theia. Use the environment variable `SCANOSS_API_KEY` to set the key securely.', + title: 'SCANOSS API Key' + } + } +}; diff --git a/packages/scanoss/src/common/index.ts b/packages/scanoss/src/common/index.ts new file mode 100644 index 0000000000000..20ced4c216794 --- /dev/null +++ b/packages/scanoss/src/common/index.ts @@ -0,0 +1,16 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** +export * from './scanoss-service'; diff --git a/packages/scanoss/src/common/scanoss-service.ts b/packages/scanoss/src/common/scanoss-service.ts new file mode 100644 index 0000000000000..a684106ba6e16 --- /dev/null +++ b/packages/scanoss/src/common/scanoss-service.ts @@ -0,0 +1,34 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** +export const SCANOSS_SERVICE_PATH = '/services/scanoss/service'; +export const ScanOSSService = Symbol('ScanOSSService'); +export interface ScanOSSResultClean { + type: 'clean'; +} +export interface ScanOSSResultMatch { + type: 'match'; + matched: string; // e.g. "75%" + url: string; + raw: unknown; +} +export interface ScanOSSResultError { + type: 'error'; + message: string; +} +export type ScanOSSResult = ScanOSSResultClean | ScanOSSResultMatch | ScanOSSResultError; +export interface ScanOSSService { + scanContent(content: string, apiKey?: string): Promise; +} diff --git a/packages/scanoss/src/node/scanoss-backend-module.ts b/packages/scanoss/src/node/scanoss-backend-module.ts new file mode 100644 index 0000000000000..176a0087fc39a --- /dev/null +++ b/packages/scanoss/src/node/scanoss-backend-module.ts @@ -0,0 +1,28 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import { ContainerModule } from '@theia/core/shared/inversify'; +import { ConnectionHandler, RpcConnectionHandler } from '@theia/core'; +import { ScanOSSService, SCANOSS_SERVICE_PATH } from '../common'; +import { ScanOSSServiceImpl } from './scanoss-service-impl'; + +export default new ContainerModule(bind => { + bind(ScanOSSServiceImpl).toSelf().inSingletonScope(); + bind(ScanOSSService).toService(ScanOSSServiceImpl); + bind(ConnectionHandler).toDynamicValue(ctx => + new RpcConnectionHandler(SCANOSS_SERVICE_PATH, () => ctx.container.get(ScanOSSService)) + ).inSingletonScope(); +}); diff --git a/packages/scanoss/src/node/scanoss-service-impl.ts b/packages/scanoss/src/node/scanoss-service-impl.ts new file mode 100644 index 0000000000000..1bc1c9c3ee163 --- /dev/null +++ b/packages/scanoss/src/node/scanoss-service-impl.ts @@ -0,0 +1,110 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +import { injectable } from '@theia/core/shared/inversify'; +import { ScanOSSResult, ScanOSSService } from '../common'; + +import { Scanner, ScannerCfg, ScannerComponent } from 'scanoss'; + +// Define our own type of what is actually returned by the scanner +interface ScanOSSScanner { + scanContents: (options: { content: string; key: T }) => Promise<{ [K in `/${T}`]: ScannerComponent[] } | null>; +} + +// Helper class to perform scans sequentially +class SequentialProcessor { + private queue: Promise = Promise.resolve() as Promise; + public async processTask(task: () => Promise): Promise { + this.queue = this.queue.then(() => task()); + return this.queue; + } +} + +@injectable() +export class ScanOSSServiceImpl implements ScanOSSService { + + private readonly processor = new SequentialProcessor(); + + async scanContent(content: string, apiKey?: string): Promise { + return this.processor.processTask(async () => this.doScanContent(content, apiKey)); + } + + async doScanContent(content: string, apiKey?: string): Promise { + const config = new ScannerCfg(); + const apiKeyToUse = apiKey || process.env.SCANOSS_API_KEY || undefined; + if (apiKeyToUse) { + config.API_KEY = apiKeyToUse; + } + const scanner = new Scanner(config); + let results = undefined; + try { + results = await (scanner as unknown as ScanOSSScanner).scanContents({ + content, + key: 'content_scanning', + }); + } catch (e) { + console.error('SCANOSS error', e); + + // map known errors to a more user-friendly message + + // Invalid API key message + if (e.message?.includes('Forbidden')) { + return { + type: 'error', + message: 'Forbidden: Please check your API key' + }; + } + // Rate limit message + // HTTP: + // HTTP Status code: 503 + // Server Response: + // 503 Unavailable. Check https://osskb.org/limit + if (e.message?.includes('https://osskb.org/limit')) { + return { + type: 'error', + message: 'You have reached the limit of the free data subscription, for a commercial subscription please contact support@scanoss.com' + }; + } + return { + type: 'error', + message: e.message + }; + } + if (!results) { + return { + type: 'error', + message: 'Scan request unsuccessful' + }; + } + + // eslint-disable-next-line no-null/no-null + console.log('SCANOSS results', JSON.stringify(results, null, 2)); + + // first result is the best result + const firstEntry = results['/content_scanning'][0]; + if (firstEntry.id === 'none') { + return { + type: 'clean' + }; + } + return { + type: 'match', + matched: firstEntry.matched, + url: firstEntry.url, + raw: firstEntry + }; + } +} diff --git a/packages/scanoss/src/package.spec.ts b/packages/scanoss/src/package.spec.ts new file mode 100644 index 0000000000000..084f1c24121bb --- /dev/null +++ b/packages/scanoss/src/package.spec.ts @@ -0,0 +1,28 @@ +// ***************************************************************************** +// Copyright (C) 2024 EclipseSource GmbH and others. +// +// This program and the accompanying materials are made available under the +// terms of the Eclipse Public License v. 2.0 which is available at +// http://www.eclipse.org/legal/epl-2.0. +// +// This Source Code may also be made available under the following Secondary +// Licenses when the conditions for such availability set forth in the Eclipse +// Public License v. 2.0 are satisfied: GNU General Public License, version 2 +// with the GNU Classpath Exception which is available at +// https://www.gnu.org/software/classpath/license.html. +// +// SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 +// ***************************************************************************** + +/* note: this bogus test file is required so that + we are able to run mocha unit tests on this + package, without having any actual unit tests in it. + This way a coverage report will be generated, + showing 0% coverage, instead of no report. + This file can be removed once we have real unit + tests in place. */ + +describe('ai-scanoss package', () => { + + it('support code coverage statistics', () => true); +}); diff --git a/packages/scanoss/tsconfig.json b/packages/scanoss/tsconfig.json new file mode 100644 index 0000000000000..b623c1e105ac7 --- /dev/null +++ b/packages/scanoss/tsconfig.json @@ -0,0 +1,16 @@ +{ + "extends": "../../configs/base.tsconfig", + "compilerOptions": { + "composite": true, + "rootDir": "src", + "outDir": "lib" + }, + "include": [ + "src" + ], + "references": [ + { + "path": "../core" + } + ] +} diff --git a/tsconfig.json b/tsconfig.json index 60ce77447142b..61f62c3c9fed2 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -87,6 +87,9 @@ { "path": "packages/ai-openai" }, + { + "path": "packages/ai-scanoss" + }, { "path": "packages/ai-terminal" }, @@ -201,6 +204,9 @@ { "path": "packages/remote" }, + { + "path": "packages/scanoss" + }, { "path": "packages/scm" }, diff --git a/yarn.lock b/yarn.lock index 51696359c618e..da2eeb0e6cca2 100644 --- a/yarn.lock +++ b/yarn.lock @@ -10,6 +10,19 @@ "@jridgewell/gen-mapping" "^0.3.5" "@jridgewell/trace-mapping" "^0.3.24" +"@anthropic-ai/sdk@^0.32.1": + version "0.32.1" + resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.32.1.tgz#d22c8ebae2adccc59d78fb416e89de337ff09014" + integrity sha512-U9JwTrDvdQ9iWuABVsMLj8nJVwAyQz6QXvgLsVhryhCEPkLsbcP/MXxm+jYcAwLoV8ESbaTTjnD4kuAFa+Hyjg== + dependencies: + "@types/node" "^18.11.18" + "@types/node-fetch" "^2.6.4" + abort-controller "^3.0.0" + agentkeepalive "^4.2.1" + form-data-encoder "1.7.2" + formdata-node "^4.3.2" + node-fetch "^2.6.7" + "@azure/abort-controller@^1.0.0": version "1.1.0" resolved "https://registry.yarnpkg.com/@azure/abort-controller/-/abort-controller-1.1.0.tgz#788ee78457a55af8a1ad342acb182383d2119249" @@ -128,19 +141,6 @@ jsonwebtoken "^9.0.0" uuid "^8.3.0" -"@anthropic-ai/sdk@^0.32.1": - version "0.32.1" - resolved "https://registry.yarnpkg.com/@anthropic-ai/sdk/-/sdk-0.32.1.tgz#d22c8ebae2adccc59d78fb416e89de337ff09014" - integrity sha512-U9JwTrDvdQ9iWuABVsMLj8nJVwAyQz6QXvgLsVhryhCEPkLsbcP/MXxm+jYcAwLoV8ESbaTTjnD4kuAFa+Hyjg== - dependencies: - "@types/node" "^18.11.18" - "@types/node-fetch" "^2.6.4" - abort-controller "^3.0.0" - agentkeepalive "^4.2.1" - form-data-encoder "1.7.2" - formdata-node "^4.3.2" - node-fetch "^2.6.7" - "@babel/code-frame@7.12.11": version "7.12.11" resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.12.11.tgz#f4ad435aa263db935b8f10f2c552d23fb716a63f" @@ -1146,6 +1146,24 @@ resolved "https://registry.yarnpkg.com/@gar/promisify/-/promisify-1.1.3.tgz#555193ab2e3bb3b6adc3d551c9c030d9e860daf6" integrity sha512-k2Ty1JcVojjJFwrg/ThKi2ujJ7XNLYaFGNB/bWT9wGR+oSMJHMa5w+CUq6p/pVrKeNNgA7pCqEcjSnHVoqJQFw== +"@grpc/grpc-js@^1.5.5": + version "1.12.4" + resolved "https://registry.yarnpkg.com/@grpc/grpc-js/-/grpc-js-1.12.4.tgz#3208808435ebf1e495f9a5c5c5a0bc3dc8c9e891" + integrity sha512-NBhrxEWnFh0FxeA0d//YP95lRFsSx2TNLEUQg4/W+5f/BMxcCjgOOIT24iD+ZB/tZw057j44DaIxja7w4XMrhg== + dependencies: + "@grpc/proto-loader" "^0.7.13" + "@js-sdsl/ordered-map" "^4.4.2" + +"@grpc/proto-loader@^0.7.13": + version "0.7.13" + resolved "https://registry.yarnpkg.com/@grpc/proto-loader/-/proto-loader-0.7.13.tgz#f6a44b2b7c9f7b609f5748c6eac2d420e37670cf" + integrity sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw== + dependencies: + lodash.camelcase "^4.3.0" + long "^5.0.0" + protobufjs "^7.2.5" + yargs "^17.7.2" + "@huggingface/inference@^2.0.0": version "2.8.1" resolved "https://registry.yarnpkg.com/@huggingface/inference/-/inference-2.8.1.tgz#e119a7746faf5ce40ebf37ec97afd51286c27ecb" @@ -1270,6 +1288,11 @@ "@jridgewell/resolve-uri" "^3.1.0" "@jridgewell/sourcemap-codec" "^1.4.14" +"@js-sdsl/ordered-map@^4.4.2": + version "4.4.2" + resolved "https://registry.yarnpkg.com/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz#9299f82874bab9e4c7f9c48d865becbfe8d6907c" + integrity sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw== + "@lerna/child-process@7.4.2": version "7.4.2" resolved "https://registry.yarnpkg.com/@lerna/child-process/-/child-process-7.4.2.tgz#a2fd013ac2150dc288270d3e0d0b850c06bec511" @@ -1887,6 +1910,59 @@ dependencies: playwright "1.48.2" +"@protobufjs/aspromise@^1.1.1", "@protobufjs/aspromise@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/aspromise/-/aspromise-1.1.2.tgz#9b8b0cc663d669a7d8f6f5d0893a14d348f30fbf" + integrity sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ== + +"@protobufjs/base64@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/base64/-/base64-1.1.2.tgz#4c85730e59b9a1f1f349047dbf24296034bb2735" + integrity sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg== + +"@protobufjs/codegen@^2.0.4": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@protobufjs/codegen/-/codegen-2.0.4.tgz#7ef37f0d010fb028ad1ad59722e506d9262815cb" + integrity sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg== + +"@protobufjs/eventemitter@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz#355cbc98bafad5978f9ed095f397621f1d066b70" + integrity sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q== + +"@protobufjs/fetch@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/fetch/-/fetch-1.1.0.tgz#ba99fb598614af65700c1619ff06d454b0d84c45" + integrity sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ== + dependencies: + "@protobufjs/aspromise" "^1.1.1" + "@protobufjs/inquire" "^1.1.0" + +"@protobufjs/float@^1.0.2": + version "1.0.2" + resolved "https://registry.yarnpkg.com/@protobufjs/float/-/float-1.0.2.tgz#5e9e1abdcb73fc0a7cb8b291df78c8cbd97b87d1" + integrity sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ== + +"@protobufjs/inquire@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/inquire/-/inquire-1.1.0.tgz#ff200e3e7cf2429e2dcafc1140828e8cc638f089" + integrity sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q== + +"@protobufjs/path@^1.1.2": + version "1.1.2" + resolved "https://registry.yarnpkg.com/@protobufjs/path/-/path-1.1.2.tgz#6cc2b20c5c9ad6ad0dccfd21ca7673d8d7fbf68d" + integrity sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA== + +"@protobufjs/pool@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/pool/-/pool-1.1.0.tgz#09fd15f2d6d3abfa9b65bc366506d6ad7846ff54" + integrity sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw== + +"@protobufjs/utf8@^1.1.0": + version "1.1.0" + resolved "https://registry.yarnpkg.com/@protobufjs/utf8/-/utf8-1.1.0.tgz#a777360b5b39a1a2e5106f8e858f2fd2d060c570" + integrity sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw== + "@puppeteer/browsers@2.3.1": version "2.3.1" resolved "https://registry.yarnpkg.com/@puppeteer/browsers/-/browsers-2.3.1.tgz#238200dbdce5c00ae28c8f2a55ac053c3be71668" @@ -2396,7 +2472,7 @@ "@types/node" "*" form-data "^4.0.0" -"@types/node@*", "@types/node@18", "@types/node@>=10.0.0", "@types/node@^10.14.22", "@types/node@^18.11.18", "@types/node@^20.9.0": +"@types/node@*", "@types/node@18", "@types/node@>=10.0.0", "@types/node@>=13.7.0", "@types/node@^10.14.22", "@types/node@^18.11.18", "@types/node@^20.9.0": version "18.19.47" resolved "https://registry.yarnpkg.com/@types/node/-/node-18.19.47.tgz#18076201ad7dd3445046df6ce9ead5fe5abd9387" integrity sha512-1f7dB3BL/bpd9tnDJrrHb66Y+cVrhxSOTGorRNdHwYTUlTay3HuTDPKo9a/4vX9pMQkhYBcAbL4jQdNlhCFP9A== @@ -3119,6 +3195,11 @@ add-stream@^1.0.0: resolved "https://registry.yarnpkg.com/add-stream/-/add-stream-1.0.0.tgz#6a7990437ca736d5e1288db92bd3266d5f5cb2aa" integrity sha512-qQLMr+8o0WC4FZGQTcJiKBVC59JylcPSrTtk6usvmIDFUOCKegapy1VHQwRbFMOFyb/inzUVqHs+eMYKDM1YeQ== +adm-zip@^0.5.9: + version "0.5.16" + resolved "https://registry.yarnpkg.com/adm-zip/-/adm-zip-0.5.16.tgz#0b5e4c779f07dedea5805cdccb1147071d94a909" + integrity sha512-TGw5yVi4saajsSEgz25grObGHEUaDrniwvA2qwSC060KfqGPdglhvPMA2lPIoxs3PQIItj2iag35fONcQqgUaQ== + advanced-mark.js@^2.6.0: version "2.6.0" resolved "https://registry.yarnpkg.com/advanced-mark.js/-/advanced-mark.js-2.6.0.tgz#86ea8b81152b543db91b1602df4e69282c3b0083" @@ -3890,6 +3971,13 @@ browser-stdout@1.3.1: resolved "https://registry.yarnpkg.com/browser-stdout/-/browser-stdout-1.3.1.tgz#baa559ee14ced73452229bad7326467c61fabd60" integrity sha512-qhAVI1+Av2X7qelOfAIYwXONood6XlZE/fXaBSmW/T5SzLAmCgzi+eiWE7fUvbHaeNBQH13UftjpXxsfLkMpgw== +browserify-zlib@^0.1.4: + version "0.1.4" + resolved "https://registry.yarnpkg.com/browserify-zlib/-/browserify-zlib-0.1.4.tgz#bb35f8a519f600e0fa6b8485241c979d0141fb2d" + integrity sha512-19OEpq7vWgsH6WkvkBJQDFvJS1uPcbFOQ4v9CU839dO+ZZXUZO6XpE6hNCqvlIIj+4fZvRiJ6DsAQ382GwiyTQ== + dependencies: + pako "~0.2.0" + browserslist@^4.21.10, browserslist@^4.23.1, browserslist@^4.23.3: version "4.23.3" resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.23.3.tgz#debb029d3c93ebc97ffbc8d9cbb03403e227c800" @@ -4301,6 +4389,13 @@ cli-cursor@3.1.0, cli-cursor@^3.1.0: dependencies: restore-cursor "^3.1.0" +cli-progress@^3.9.1: + version "3.12.0" + resolved "https://registry.yarnpkg.com/cli-progress/-/cli-progress-3.12.0.tgz#807ee14b66bcc086258e444ad0f19e7d42577942" + integrity sha512-tRkV3HJ1ASwm19THiiLIXLO7Im7wlTuKnvkYaTkyoAPefqjNg7W7DHKUlGRxy9vxDvbyCYQkQozvptuMkGCg8A== + dependencies: + string-width "^4.2.3" + cli-spinners@2.6.1: version "2.6.1" resolved "https://registry.yarnpkg.com/cli-spinners/-/cli-spinners-2.6.1.tgz#adc954ebe281c37a6319bfa401e6dd2488ffb70d" @@ -4438,6 +4533,11 @@ commander@2.6.0: resolved "https://registry.yarnpkg.com/commander/-/commander-2.6.0.tgz#9df7e52fb2a0cb0fb89058ee80c3104225f37e1d" integrity sha512-PhbTMT+ilDXZKqH8xbvuUY2ZEQNef0Q7DKxgoEKb4ccytsdvVVJmYqR0sGbi96nxU6oGrwEIQnclpK2NBZuQlg== +commander@^11.1.0: + version "11.1.0" + resolved "https://registry.yarnpkg.com/commander/-/commander-11.1.0.tgz#62fdce76006a68e5c1ab3314dc92e800eb83d906" + integrity sha512-yPVavfyCcRhmorC7rWlkHn15b4wDVgVmBA7kV4QVBsF7kv/9TKJAbAXVTxvTnwP8HHKjRCJDClKbciiYS7p0DQ== + commander@^2.12.1, commander@^2.20.0, commander@^2.8.1: version "2.20.3" resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" @@ -5321,6 +5421,16 @@ duplexer@^0.1.1, duplexer@~0.1.1: resolved "https://registry.yarnpkg.com/duplexer/-/duplexer-0.1.2.tgz#3abe43aef3835f8ae077d136ddce0f276b0400e6" integrity sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg== +duplexify@^3.5.0, duplexify@^3.6.0: + version "3.7.1" + resolved "https://registry.yarnpkg.com/duplexify/-/duplexify-3.7.1.tgz#2a4df5317f6ccfd91f86d6fd25d8d8a103b88309" + integrity sha512-07z8uv2wMyS51kKhD1KsdXJg5WQ6t93RneqRxUHnskXVtlYYkLqM0gqStQZ3pj073g687jPCHrqNfCzawLYh5g== + dependencies: + end-of-stream "^1.0.0" + inherits "^2.0.1" + readable-stream "^2.0.0" + stream-shift "^1.0.0" + eastasianwidth@^0.2.0: version "0.2.0" resolved "https://registry.yarnpkg.com/eastasianwidth/-/eastasianwidth-0.2.0.tgz#696ce2ec0aa0e6ea93a397ffcf24aa7840c827cb" @@ -5942,7 +6052,7 @@ event-target-shim@^5.0.0: resolved "https://registry.yarnpkg.com/event-target-shim/-/event-target-shim-5.0.1.tgz#5d4d3ebdf9583d63a5333ce2deb7480ab2b05789" integrity sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ== -eventemitter3@^4.0.0, eventemitter3@^4.0.4: +eventemitter3@^4.0.0, eventemitter3@^4.0.4, eventemitter3@^4.0.7: version "4.0.7" resolved "https://registry.yarnpkg.com/eventemitter3/-/eventemitter3-4.0.7.tgz#2de9b68f6528d5644ef5c59526a1b4a07306169f" integrity sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw== @@ -6809,6 +6919,11 @@ globby@^7.1.1: pify "^3.0.0" slash "^1.0.0" +google-protobuf@^3.19.4: + version "3.21.4" + resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.21.4.tgz#2f933e8b6e5e9f8edde66b7be0024b68f77da6c9" + integrity sha512-MnG7N936zcKTco4Jd2PX2U96Kf9PxygAPKBug+74LHzmHXmceN16MmRcdgZv+DGef/S9YvQAfRsNCn4cjf9yyQ== + gopd@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/gopd/-/gopd-1.0.1.tgz#29ff76de69dac7489b7c0918a5788e56477c332c" @@ -6843,6 +6958,18 @@ graphemer@^1.4.0: resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== +gunzip-maybe@^1.4.2: + version "1.4.2" + resolved "https://registry.yarnpkg.com/gunzip-maybe/-/gunzip-maybe-1.4.2.tgz#b913564ae3be0eda6f3de36464837a9cd94b98ac" + integrity sha512-4haO1M4mLO91PW57BMsDFf75UmwoRX0GkdD+Faw+Lr+r/OZrOCS0pIBwOL1xCKQqnQzbNFGgK2V2CpBUPeFNTw== + dependencies: + browserify-zlib "^0.1.4" + is-deflate "^1.0.0" + is-gzip "^1.0.0" + peek-stream "^1.1.0" + pumpify "^1.3.3" + through2 "^2.0.3" + handlebars@^4.7.7: version "4.7.8" resolved "https://registry.yarnpkg.com/handlebars/-/handlebars-4.7.8.tgz#41c42c18b1be2365439188c77c6afae71c0cd9e9" @@ -7235,7 +7362,7 @@ inflight@^1.0.4: once "^1.3.0" wrappy "1" -inherits@2, inherits@2.0.4, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: +inherits@2, inherits@2.0.4, inherits@^2.0.1, inherits@^2.0.3, inherits@^2.0.4, inherits@~2.0.0, inherits@~2.0.3: version "2.0.4" resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== @@ -7394,6 +7521,11 @@ is-date-object@^1.0.1, is-date-object@^1.0.5: dependencies: has-tostringtag "^1.0.0" +is-deflate@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-deflate/-/is-deflate-1.0.0.tgz#c862901c3c161fb09dac7cdc7e784f80e98f2f14" + integrity sha512-YDoFpuZWu1VRXlsnlYMzKyVRITXj7Ej/V9gXQ2/pAe7X1J7M/RNOqaIYi6qUn+B7nGyB9pDXrv02dsB58d2ZAQ== + is-docker@^2.0.0, is-docker@^2.1.1: version "2.2.1" resolved "https://registry.yarnpkg.com/is-docker/-/is-docker-2.2.1.tgz#33eeabe23cfe86f14bde4408a02c0cfb853acdaa" @@ -7447,6 +7579,11 @@ is-glob@^4.0.0, is-glob@^4.0.1, is-glob@^4.0.3, is-glob@~4.0.1: dependencies: is-extglob "^2.1.1" +is-gzip@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/is-gzip/-/is-gzip-1.0.0.tgz#6ca8b07b99c77998025900e555ced8ed80879a83" + integrity sha512-rcfALRIb1YewtnksfRIHGcIY93QnK8BIQ/2c9yDYcG/Y6+vRoJuTWBmmSEbyLLYtXm7q35pHOHbZFQBaLrhlWQ== + is-interactive@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" @@ -7648,6 +7785,11 @@ isarray@~1.0.0: resolved "https://registry.yarnpkg.com/isarray/-/isarray-1.0.0.tgz#bb935d48582cba168c06834957a54a3e07124f11" integrity sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ== +isbinaryfile@^4.0.8: + version "4.0.10" + resolved "https://registry.yarnpkg.com/isbinaryfile/-/isbinaryfile-4.0.10.tgz#0c5b5e30c2557a2f06febd37b7322946aaee42b3" + integrity sha512-iHrqe5shvBUcFbmZq9zOQHBoeOhZJu6RQGrDpBgenUm/Am+F3JM2MgQj+rK3Z601fzrL5gLZWtAPH2OBaSVcyw== + isexe@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/isexe/-/isexe-2.0.0.tgz#e8fbf374dc556ff8947a10dcb0572d633f2cfa10" @@ -8324,6 +8466,11 @@ locate-path@^6.0.0: dependencies: p-locate "^5.0.0" +lodash.camelcase@^4.3.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/lodash.camelcase/-/lodash.camelcase-4.3.0.tgz#b28aa6288a2b9fc651035c7711f65ab6190331a6" + integrity sha512-TwuEnCnxbc3rAvhf/LbG7tJUDzhqXyFnv3dtzLOPgCG/hODL7WFnsbwktkD7yUV0RrreP/l1PALq/YSg6VvjlA== + lodash.clonedeep@^4.5.0: version "4.5.0" resolved "https://registry.yarnpkg.com/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz#e23f3f9c4f8fbdde872529c1071857a086e5ccef" @@ -8447,6 +8594,11 @@ long@^4.0.0: resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== +long@^5.0.0: + version "5.2.3" + resolved "https://registry.yarnpkg.com/long/-/long-5.2.3.tgz#a3ba97f3877cf1d778eccbcb048525ebb77499e1" + integrity sha512-lcHwpNoggQTObv5apGNCTdJrO69eHOZMi4BNC+rTLER8iHAqGrUVeLh/irVIM7zTw2bOXA8T6uNPeujwOLg/2Q== + loose-envify@^1.1.0, loose-envify@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/loose-envify/-/loose-envify-1.4.0.tgz#71ee51fa7be4caec1a63839f7e682d8132d30caf" @@ -9205,7 +9357,7 @@ node-fetch@2.6.7: dependencies: whatwg-url "^5.0.0" -node-fetch@^2.6.7: +node-fetch@^2.6.1, node-fetch@^2.6.7: version "2.7.0" resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.7.0.tgz#d0f0fa6e3e2dc1d27efcd8ad99d550bda94d187d" integrity sha512-c4FRfUm/dbcWZ7U+1Wq0AwCyFL+3nt2bEw05wfxSz+DWpWsitgmSgYmy2dQdWyKC1694ELPqMs/YzUSNozLt8A== @@ -9952,6 +10104,11 @@ package-json-from-dist@^1.0.0: resolved "https://registry.yarnpkg.com/package-json-from-dist/-/package-json-from-dist-1.0.1.tgz#4f1471a010827a86f94cfd9b0727e36d267de505" integrity sha512-UEZIS3/by4OC8vL3P2dTXRETpebLI2NiI5vIrjaD/5UtrkFX/tNbwjTSRAGC/+7CAo2pIcBaRgWmcBBHcsaCIw== +packageurl-js@^0.0.5: + version "0.0.5" + resolved "https://registry.yarnpkg.com/packageurl-js/-/packageurl-js-0.0.5.tgz#a48c9e5ca6855cd23660257ad2b0199593b3373a" + integrity sha512-BISQVKLiu7EsWF5Qhx8OvX6K5vOfFcYuQBggFfrF2dHu+/Z2snuabilb0EyLvHZH0XXqbEz20pqFRonTt8z6QA== + pacote@^15.2.0: version "15.2.0" resolved "https://registry.yarnpkg.com/pacote/-/pacote-15.2.0.tgz#0f0dfcc3e60c7b39121b2ac612bf8596e95344d3" @@ -9976,6 +10133,11 @@ pacote@^15.2.0: ssri "^10.0.0" tar "^6.1.11" +pako@~0.2.0: + version "0.2.9" + resolved "https://registry.yarnpkg.com/pako/-/pako-0.2.9.tgz#f3f7522f4ef782348da8161bad9ecfd51bf83a75" + integrity sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA== + parent-module@^1.0.0: version "1.0.1" resolved "https://registry.yarnpkg.com/parent-module/-/parent-module-1.0.1.tgz#691d2709e78c79fae3a156622452d00762caaaa2" @@ -10164,6 +10326,15 @@ pdfobject@^2.0.201604172: resolved "https://registry.yarnpkg.com/pdfobject/-/pdfobject-2.3.0.tgz#467b4ffcd621518aa0e66fc191fdd669f3118b06" integrity sha512-w/9pXDXTDs3IDmOri/w8lM/w6LHR0/F4fcBLLzH+4csSoyshQ5su0TE7k0FLHZO7aOjVLDGecqd1M89+PVpVAA== +peek-stream@^1.1.0: + version "1.1.3" + resolved "https://registry.yarnpkg.com/peek-stream/-/peek-stream-1.1.3.tgz#3b35d84b7ccbbd262fff31dc10da56856ead6d67" + integrity sha512-FhJ+YbOSBb9/rIl2ZeE/QHEsWn7PqNYt8ARAY3kIgNGOk13g9FGyIY6JIl/xB/3TFRVoTv5as0l11weORrTekA== + dependencies: + buffer-from "^1.0.0" + duplexify "^3.5.0" + through2 "^2.0.3" + pend@~1.2.0: version "1.2.0" resolved "https://registry.yarnpkg.com/pend/-/pend-1.2.0.tgz#7a57eb550a6783f9115331fcf4663d5c8e007a50" @@ -10448,6 +10619,24 @@ properties@^1.2.1: resolved "https://registry.yarnpkg.com/properties/-/properties-1.2.1.tgz#0ee97a7fc020b1a2a55b8659eda4aa8d869094bd" integrity sha512-qYNxyMj1JeW54i/EWEFsM1cVwxJbtgPp8+0Wg9XjNaK6VE/c4oRi6PNu5p7w1mNXEIQIjV5Wwn8v8Gz82/QzdQ== +protobufjs@^7.2.5: + version "7.4.0" + resolved "https://registry.yarnpkg.com/protobufjs/-/protobufjs-7.4.0.tgz#7efe324ce9b3b61c82aae5de810d287bc08a248a" + integrity sha512-mRUWCc3KUU4w1jU8sGxICXH/gNS94DvI1gxqDvBzhj1JpcsimQkYiOJfwsPUykUI5ZaspFbSgmBLER8IrQ3tqw== + dependencies: + "@protobufjs/aspromise" "^1.1.2" + "@protobufjs/base64" "^1.1.2" + "@protobufjs/codegen" "^2.0.4" + "@protobufjs/eventemitter" "^1.1.0" + "@protobufjs/fetch" "^1.1.0" + "@protobufjs/float" "^1.0.2" + "@protobufjs/inquire" "^1.1.0" + "@protobufjs/path" "^1.1.2" + "@protobufjs/pool" "^1.1.0" + "@protobufjs/utf8" "^1.1.0" + "@types/node" ">=13.7.0" + long "^5.0.0" + protocols@^2.0.0, protocols@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/protocols/-/protocols-2.0.1.tgz#8f155da3fc0f32644e83c5782c8e8212ccf70a86" @@ -10510,6 +10699,14 @@ pump@^1.0.0: end-of-stream "^1.1.0" once "^1.3.1" +pump@^2.0.0: + version "2.0.1" + resolved "https://registry.yarnpkg.com/pump/-/pump-2.0.1.tgz#12399add6e4cf7526d973cbc8b5ce2e2908b3909" + integrity sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA== + dependencies: + end-of-stream "^1.1.0" + once "^1.3.1" + pump@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/pump/-/pump-3.0.0.tgz#b4a2116815bde2f4e1ea602354e8c75565107a64" @@ -10518,6 +10715,15 @@ pump@^3.0.0: end-of-stream "^1.1.0" once "^1.3.1" +pumpify@^1.3.3: + version "1.5.1" + resolved "https://registry.yarnpkg.com/pumpify/-/pumpify-1.5.1.tgz#36513be246ab27570b1a374a5ce278bfd74370ce" + integrity sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ== + dependencies: + duplexify "^3.6.0" + inherits "^2.0.3" + pump "^2.0.0" + punycode@^2.1.0, punycode@^2.1.1, punycode@^2.3.0: version "2.3.1" resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.3.1.tgz#027422e2faec0b25e1549c3e1bd8309b9133b6e5" @@ -11151,7 +11357,7 @@ sanitize-filename@^1.6.3: dependencies: truncate-utf8-bytes "^1.0.0" -sax@>=0.6.0: +sax@>=0.6.0, sax@^1.2.4: version "1.4.1" resolved "https://registry.yarnpkg.com/sax/-/sax-1.4.1.tgz#44cc8988377f126304d3b3fc1010c733b929ef0f" integrity sha512-+aWOz7yVScEGoKNd4PA10LZ8sk0A/z5+nXQG5giUO5rprX9jgYsTdov9qCchZiPIZezbZH+jRut8nPodFAX4Jg== @@ -11175,6 +11381,32 @@ sb-scandir@^3.1.0: dependencies: sb-promise-queue "^2.1.0" +scanoss@^0.15.2: + version "0.15.3" + resolved "https://registry.yarnpkg.com/scanoss/-/scanoss-0.15.3.tgz#f8ca1d43c9172f1c5f50e5f2e9305007ea27ad6d" + integrity sha512-d99V1jAzAavFZVPzcviXMv5jmF55Z8mfR0FYhShuwvUK+IFkeLB6cllmlvP/tzp3OpkRexBtBlThoc3DHIodSA== + dependencies: + "@grpc/grpc-js" "^1.5.5" + abort-controller "^3.0.0" + adm-zip "^0.5.9" + cli-progress "^3.9.1" + commander "^11.1.0" + eventemitter3 "^4.0.7" + form-data "^4.0.0" + google-protobuf "^3.19.4" + gunzip-maybe "^1.4.2" + isbinaryfile "^4.0.8" + node-fetch "^2.6.1" + p-queue "6.6.2" + packageurl-js "^0.0.5" + proxy-agent "^6.4.0" + sort-paths "^1.1.1" + syswide-cas "^5.3.0" + tar "^6.1.11" + tar-stream "^2.2.0" + uuid "^9.0.0" + xml-js "^1.6.11" + scheduler@^0.23.2: version "0.23.2" resolved "https://registry.yarnpkg.com/scheduler/-/scheduler-0.23.2.tgz#414ba64a3b282892e944cf2108ecc078d115cdc3" @@ -11573,6 +11805,13 @@ sort-keys@^2.0.0: dependencies: is-plain-obj "^1.0.0" +sort-paths@^1.1.1: + version "1.1.1" + resolved "https://registry.yarnpkg.com/sort-paths/-/sort-paths-1.1.1.tgz#f78ea71a8824faf45b66a8026a2a8f7332c6a66f" + integrity sha512-khy0t3pqjZPcQK5hId33EnxlzkFhB5JsxBWKj2IixGwP9SdoRl36eKJC25GgbF1vrXAzLnJsh/0+QScksUZTDg== + dependencies: + split-retain "^1.0.1" + source-map-js@^0.6.2: version "0.6.2" resolved "https://registry.yarnpkg.com/source-map-js/-/source-map-js-0.6.2.tgz#0bb5de631b41cfbda6cfba8bd05a80efdfd2385e" @@ -11658,6 +11897,11 @@ split-ca@^1.0.1: resolved "https://registry.yarnpkg.com/split-ca/-/split-ca-1.0.1.tgz#6c83aff3692fa61256e0cd197e05e9de157691a6" integrity sha512-Q5thBSxp5t8WPTTJQS59LrGqOZqOsrhDGDVm8azCqIBjSBd7nd9o2PM+mDulQQkh8h//4U6hFZnc/mul8t5pWQ== +split-retain@^1.0.1: + version "1.0.1" + resolved "https://registry.yarnpkg.com/split-retain/-/split-retain-1.0.1.tgz#c7028b5bafd54ee53ae2c267e608da8f605eb2a6" + integrity sha512-TAsNK+sKP2+A6FLGiSWXPj0gYUF6Ls+YKG6pm+vy/0vzmSxAPrQNpZaS8/TqeObs4YxHHgLQGxeW0azfrK9Ebg== + split2@^3.2.2: version "3.2.2" resolved "https://registry.yarnpkg.com/split2/-/split2-3.2.2.tgz#bf2cf2a37d838312c249c89206fd7a17dd12365f" @@ -11745,6 +11989,11 @@ stream-combiner@~0.0.4: dependencies: duplexer "~0.1.1" +stream-shift@^1.0.0: + version "1.0.3" + resolved "https://registry.yarnpkg.com/stream-shift/-/stream-shift-1.0.3.tgz#85b8fab4d71010fc3ba8772e8046cc49b8a3864b" + integrity sha512-76ORR0DO1o1hlKwTbi/DM3EXWGf3ZJYO8cXX5RJwnul2DEg2oyoZyjLNoQM8WsvZiFKCRfC1O0J7iCvie3RZmQ== + streamsearch@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/streamsearch/-/streamsearch-1.1.0.tgz#404dd1e2247ca94af554e841a8ef0eaa238da764" @@ -12018,6 +12267,11 @@ symbol-tree@^3.2.4: resolved "https://registry.yarnpkg.com/symbol-tree/-/symbol-tree-3.2.4.tgz#430637d248ba77e078883951fb9aa0eed7c63fa2" integrity sha512-9QNk5KwDF+Bvz+PyObkmSYjI5ksVUYtjW7AU22r2NKcfLJcXp96hkDWU3+XndOsUb+AQ9QhfzfCT2O+CNWT5Tw== +syswide-cas@^5.3.0: + version "5.3.0" + resolved "https://registry.yarnpkg.com/syswide-cas/-/syswide-cas-5.3.0.tgz#ef24b8580caa1c6d985b88cacfaa35db16982ed5" + integrity sha512-+RLgS6VInsX8rBpL+gy5qpa7phngecbK7NABelBZpqYpBTwOIK1y7CqHlXK5Vy/rA4erD9q/FyKzMjx2uX3zYg== + table@^6.0.9: version "6.8.2" resolved "https://registry.yarnpkg.com/table/-/table-6.8.2.tgz#c5504ccf201213fa227248bdc8c5569716ac6c58" @@ -12199,7 +12453,7 @@ text-table@^0.2.0: resolved "https://registry.yarnpkg.com/text-table/-/text-table-0.2.0.tgz#7f5ee823ae805207c00af2df4a84ec3fcfa570b4" integrity sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw== -through2@^2.0.0: +through2@^2.0.0, through2@^2.0.3: version "2.0.5" resolved "https://registry.yarnpkg.com/through2/-/through2-2.0.5.tgz#01c1e39eb31d07cb7d03a96a70823260b23132cd" integrity sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ== @@ -13310,6 +13564,13 @@ xdg-trashdir@^3.1.0: user-home "^2.0.0" xdg-basedir "^4.0.0" +xml-js@^1.6.11: + version "1.6.11" + resolved "https://registry.yarnpkg.com/xml-js/-/xml-js-1.6.11.tgz#927d2f6947f7f1c19a316dd8eea3614e8b18f8e9" + integrity sha512-7rVi2KMfwfWFl+GpPg6m80IVMWXLRjO+PxTq7V2CDhoGak0wzYzFgUY2m4XJ47OGdXd8eLE8EmwfAmdjw7lC1g== + dependencies: + sax "^1.2.4" + xml-name-validator@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-4.0.0.tgz#79a006e2e63149a8600f15430f0a4725d1524835"