Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions docs/API-Reference/language/CodeInspection.md
Original file line number Diff line number Diff line change
Expand Up @@ -163,7 +163,7 @@ Each error object in the results should have the following structure:
htmlMessage:string,
type:?Type ,
fix: { // an optional fix, if present will show the fix button
replace: "text to replace the offset given below",
replaceText: "text to replace the offset given below",
rangeOffset: {
start: number,
end: number
Expand Down Expand Up @@ -194,7 +194,7 @@ Each error object in the results should have the following structure:
| htmlMessage | <code>string</code> | The error message to be displayed as HTML. |
| type | [<code>Type</code>](#Type) | The type of the error. Defaults to `Type.WARNING` if unspecified. |
| fix | <code>Object</code> | An optional fix object. |
| fix.replace | <code>string</code> | The text to replace the error with. |
| fix.replaceText | <code>string</code> | The text to replace the error with. |
| fix.rangeOffset | <code>Object</code> | The range within the text to replace. |
| fix.rangeOffset.start | <code>number</code> | The start offset of the range. |
| fix.rangeOffset.end | <code>number</code> | The end offset of the range. If no errors are found, return either `null`(treated as file is problem free) or an object with a zero-length `errors` array. Always use `message` to safely display the error as text. If you want to display HTML error message, then explicitly use `htmlMessage` to display it. Both `message` and `htmlMessage` can be used simultaneously. After scanning the file, if you need to omit the lint result, return or resolve with `{isIgnored: true}`. This prevents the file from being marked with a no errors tick mark in the status bar and excludes the linter from the problems panel. |
Expand Down
30 changes: 30 additions & 0 deletions docs/API-Reference/widgets/NotificationUI.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ The `createFromTemplate` API can be configured with numerous options. See API op
* [.createToastFromTemplate(title, template, [options])](#module_widgets/NotificationUI..createToastFromTemplate) ⇒ <code>Notification</code>
* [.showToastOn(containerOrSelector, template, [options])](#module_widgets/NotificationUI..showToastOn) ⇒ <code>Notification</code>
* [.showHUD(iconClass, label, [options])](#module_widgets/NotificationUI..showHUD) ⇒ <code>Notification</code>
* [.hideRichTooltip()](#module_widgets/NotificationUI..hideRichTooltip) : <code>function</code>
* [.attachRichTooltip(elements, html, [options])](#module_widgets/NotificationUI..attachRichTooltip) ⇒ <code>Object</code>

<a name="module_widgets/NotificationUI..API"></a>

Expand Down Expand Up @@ -188,3 +190,31 @@ NotificationUI.showHUD("fa-solid fa-magnifying-glass-plus", "110%");
| label | <code>string</code> | Text to display below the icon (e.g. "110%"). |
| [options] | <code>Object</code> | optional, supported options: * `autoCloseTimeS` - Time in seconds after which the HUD auto-closes. Default is 1. |

<a name="module_widgets/NotificationUI..hideRichTooltip"></a>

### widgets/NotificationUI.hideRichTooltip() : <code>function</code>
Hide the currently showing rich tooltip (if any).

**Kind**: inner method of [<code>widgets/NotificationUI</code>](#module_widgets/NotificationUI)
<a name="module_widgets/NotificationUI..attachRichTooltip"></a>

### widgets/NotificationUI.attachRichTooltip(elements, html, [options]) ⇒ <code>Object</code>
Attaches a rich (HTML-capable) hover tooltip to the given element(s). The tooltip is
Phoenix-themed for both light and dark themes, positioned beside the element, clamped to the
viewport, and attached to `<body>` so scrolling containers cannot clip it.

```js
NotificationUI.attachRichTooltip($(".my-info-icon"), "<b>Hello</b> world");
// or compute content per element on show:
NotificationUI.attachRichTooltip($(".my-info-icon"), el => $(el).attr("data-info"));
```

**Kind**: inner method of [<code>widgets/NotificationUI</code>](#module_widgets/NotificationUI)
**Returns**: <code>Object</code> - call `detach()` to unbind the handlers and hide the tooltip

| Param | Type | Description |
| --- | --- | --- |
| elements | <code>jQuery</code> \| <code>Element</code> \| <code>string</code> | element(s) or selector to attach to |
| html | <code>string</code> \| <code>function</code> | TRUSTED html string (escape untrusted parts yourself), or a function returning it for the hovered element |
| [options] | <code>Object</code> | optional, supported options: * `showDelayMs` - hover delay before the tooltip appears. Default 250. |

44 changes: 43 additions & 1 deletion src-node/lsp-client.js
Original file line number Diff line number Diff line change
Expand Up @@ -142,12 +142,54 @@ function handleMessage(serverId, msg) {
} else {
resolve(msg.result);
}
} else if (msg.method && msg.id !== undefined) {
// Server-initiated REQUEST: answer it right here so the server never awaits a reply
// forever (the browser side has no response path; an unanswered request can stall the
// server's own processing - e.g. vscode-json-language-server pulling configuration).
_respondToServerRequest(serverId, server, msg);
} else if (msg.method) {
// Notification or server-initiated request - forward to the browser.
// Notification - forward to the browser (e.g. textDocument/publishDiagnostics).
nodeConnector.triggerPeer('lspNotification', { serverId, ...msg });
}
}

/**
* Answer a server-initiated request with a benign, spec-shaped reply. We advertise minimal client
* capabilities (no dynamic registration, workspace.configuration=false), so servers should rarely
* send these - this is the safety net that guarantees no server hangs awaiting a reply.
* @param {string} serverId - The server identifier (for logging)
* @param {Object} server - The server state object
* @param {Object} msg - The incoming JSON-RPC request (method + id)
*/
function _respondToServerRequest(serverId, server, msg) {
let response;
switch (msg.method) {
case 'workspace/configuration':
// Result must be an array matching params.items length; null entries mean "no config".
response = {
jsonrpc: '2.0', id: msg.id,
result: ((msg.params && msg.params.items) || []).map(() => null)
};
break;
case 'client/registerCapability':
case 'client/unregisterCapability':
case 'window/workDoneProgress/create':
case 'window/showMessageRequest':
response = { jsonrpc: '2.0', id: msg.id, result: null };
break;
default:
response = {
jsonrpc: '2.0', id: msg.id,
error: { code: -32601, message: `Method not handled by Phoenix LSP client: ${msg.method}` }
};
}
try {
server.process.stdin.write(encode(response));
} catch (e) {
console.error(`[lsp-client][${serverId}] failed to answer ${msg.method}:`, e.message);
}
}

/**
* Ping endpoint to verify the LSP connector is alive.
* @returns {Promise<Object>} Status and list of active servers
Expand Down
52 changes: 52 additions & 0 deletions src-node/npm-intel.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
/*
* GNU AGPL-3.0 License
*
* Copyright (c) 2021 - present core.ai . All rights reserved.
*
* This program is free software: you can redistribute it and/or modify it
* under the terms of the GNU Affero General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License
* for more details.
*
* You should have received a copy of the GNU Affero General Public License
* along with this program. If not, see https://opensource.org/licenses/AGPL-3.0.
*
*/

/**
* npm-intel - node-side helper for npm security-advisory lookups. The registry's bulk advisory
* endpoint is POST-only without CORS headers, so the browser context cannot call it directly;
* the JSONSupport extension routes the request here on desktop builds.
*
* Lazy-loaded via NodeUtils._loadNodeExtensionModule("./npm-intel") on first use - keep this
* module free of heavyweight requires so it adds nothing to node boot.
*/

const ADVISORY_BULK_URL = "https://registry.npmjs.org/-/npm/v1/security/advisories/bulk";

/**
* POST the bulk advisory query to the npm registry.
* @param {Object} params
* @param {Object<string, string[]>} params.body - map of package name -> array of exact versions
* @returns {Promise<Object>} the registry's response: package name -> advisory array
*/
async function fetchAdvisoriesBulk({ body }) {
const response = await fetch(ADVISORY_BULK_URL, {
method: "POST",
headers: { "content-type": "application/json" },
body: JSON.stringify(body)
});
if (!response.ok) {
throw new Error(`advisory fetch failed: ${response.status}`);
}
return response.json();
}

exports.fetchAdvisoriesBulk = fetchAdvisoriesBulk;

global.createNodeConnector("ph-npm-intel", exports);
Loading
Loading