feat(ui/scripts): SCADA-specific Monaco extensions
Wave 3 of the Monaco/Roslyn integration. Adds the four extensions
agreed in the design Q&A:
1. Parameters["..."] keys — when the cursor is inside a string
literal that's the index of a Parameters[] element-access,
completions return the parameter names declared in the form's
ParameterListEditor.
2. CallShared("...") names — when the cursor is inside a string
literal argument to a CallShared(...) invocation, completions
return the names of all shared scripts (resolved server-side
via SharedScriptService).
3. CallScript("...") names — same shape, but uses sibling-script
names passed from the form (TemplateEdit's _scripts list).
4. Forbidden-API diagnostic — squiggles uses of the documented
script trust model bans: System.IO / Diagnostics / Reflection /
Net / Threading.Thread namespaces, plus the named types File,
Directory, Process, Thread, Socket, etc. New diagnostic codes
SCADA001 (using directive) and SCADA002 (type identifier).
ScriptAnalysisService gains a SharedScriptService dependency
(scoped, hence the analyzer is now scoped too); CompletionsRequest
carries DeclaredParameters and SiblingScripts; Complete is now async.
MonacoEditor.razor exposes DeclaredParameters / SiblingScripts
parameters plus a [JSInvokable] GetContext() so the JS side asks
for the latest form state on every completion request. The
provider in monaco-init.js looks up the owning editor from the
internal editors map and forwards the context.
ScriptParameterNames helper parses the ParameterListEditor JSON
into a name list — used by SharedScriptForm, ApiMethodForm, and
TemplateEdit's Add-Script form to populate the Monaco context.
Smoke-verified via direct fetch + Monaco trigger:
- var x = Parameters[" → popup: "name" (declared parameter)
- var y = CallShared(" → popup: GetWeather, Greet
- using System.IO; → SCADA001 squiggle
- Process.Start(...) → SCADA002 squiggle
- File.ReadAllText(...) → SCADA002 squiggle
Also fixed: ScriptAnalysisService scoped (was singleton, broke DI
because SharedScriptService is scoped); JS normalizes Pascal-case
context keys from Blazor's record serialization to camel-case for
the request body.
This commit is contained in:
@@ -41,6 +41,25 @@
|
||||
triggerCharacters: [".", "(", "\""],
|
||||
provideCompletionItems: async function (model, position) {
|
||||
try {
|
||||
// Find which editor instance owns this model so we can ask
|
||||
// the Blazor side for the latest form context.
|
||||
// Blazor JS interop serializes records as PascalCase; we
|
||||
// normalize to camelCase here.
|
||||
let ctx = { declaredParameters: [], siblingScripts: [] };
|
||||
for (const key in editors) {
|
||||
if (editors[key].editor.getModel() === model) {
|
||||
try {
|
||||
const got = await editors[key].dotNetRef.invokeMethodAsync("GetContext");
|
||||
if (got) {
|
||||
ctx = {
|
||||
declaredParameters: got.DeclaredParameters || got.declaredParameters || [],
|
||||
siblingScripts: got.SiblingScripts || got.siblingScripts || []
|
||||
};
|
||||
}
|
||||
} catch (e) { /* fall through */ }
|
||||
break;
|
||||
}
|
||||
}
|
||||
const resp = await fetch("/api/script-analysis/completions", {
|
||||
method: "POST",
|
||||
credentials: "same-origin",
|
||||
@@ -48,7 +67,9 @@
|
||||
body: JSON.stringify({
|
||||
codeText: model.getValue(),
|
||||
line: position.lineNumber,
|
||||
column: position.column
|
||||
column: position.column,
|
||||
declaredParameters: ctx.declaredParameters,
|
||||
siblingScripts: ctx.siblingScripts
|
||||
})
|
||||
});
|
||||
if (!resp.ok) return { suggestions: [] };
|
||||
|
||||
Reference in New Issue
Block a user