Merge branch 'main' into joshmgross/matrix-context-validation
This commit is contained in:
@@ -0,0 +1,61 @@
|
||||
# Simple workflow for deploying static content to GitHub Pages
|
||||
name: Deploy static content to Pages
|
||||
|
||||
on:
|
||||
# Runs on pushes targeting the default branch
|
||||
push:
|
||||
branches:
|
||||
- main
|
||||
|
||||
# Allows you to run this workflow manually from the Actions tab
|
||||
workflow_dispatch:
|
||||
|
||||
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
|
||||
permissions:
|
||||
contents: read
|
||||
pages: write
|
||||
id-token: write
|
||||
packages: read
|
||||
|
||||
# Allow one concurrent deployment
|
||||
concurrency:
|
||||
group: "pages"
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
# Single deploy job since we're just deploying
|
||||
deploy:
|
||||
environment:
|
||||
name: github-pages
|
||||
url: ${{ steps.deployment.outputs.page_url }}
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v3
|
||||
- uses: actions/setup-node@v3
|
||||
with:
|
||||
node-version: 16
|
||||
registry-url: 'https://npm.pkg.github.com'
|
||||
scope: '@github'
|
||||
|
||||
- run: npm ci
|
||||
env:
|
||||
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: build dependencies
|
||||
run: |
|
||||
npm run build -ws
|
||||
|
||||
- name: copy index
|
||||
run: |
|
||||
cp ./public/index.html ./dist/index.html
|
||||
working-directory: ./browser-playground
|
||||
- name: Setup Pages
|
||||
uses: actions/configure-pages@v2
|
||||
- name: Upload artifact
|
||||
uses: actions/upload-pages-artifact@v1
|
||||
with:
|
||||
path: './browser-playground/dist'
|
||||
- name: Deploy to GitHub Pages
|
||||
id: deployment
|
||||
uses: actions/deploy-pages@v1
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@github/actions-languageserver",
|
||||
"version": "0.1.39",
|
||||
"version": "0.1.41",
|
||||
"description": "Language server for GitHub Actions",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
@@ -38,7 +38,7 @@
|
||||
"prettier-fix": "prettier --write ."
|
||||
},
|
||||
"dependencies": {
|
||||
"@github/actions-languageservice": "^0.1.39",
|
||||
"@github/actions-languageservice": "^0.1.41",
|
||||
"@octokit/rest": "^19.0.5",
|
||||
"vscode-languageserver": "^8.0.2",
|
||||
"vscode-languageserver-textdocument": "^1.0.7"
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
import { hover } from "@github/actions-languageservice/hover";
|
||||
import { registerLogger, setLogLevel } from "@github/actions-languageservice/log";
|
||||
import { validate } from "@github/actions-languageservice/validate";
|
||||
import {
|
||||
CompletionItem,
|
||||
Connection,
|
||||
Hover,
|
||||
HoverParams,
|
||||
InitializeParams,
|
||||
InitializeResult,
|
||||
TextDocumentPositionParams,
|
||||
TextDocuments,
|
||||
TextDocumentSyncKind
|
||||
} from "vscode-languageserver";
|
||||
import { TextDocument } from "vscode-languageserver-textdocument";
|
||||
import { contextProviders } from "./context-providers";
|
||||
import { InitializationOptions, RepositoryContext } from "./initializationOptions";
|
||||
import { onCompletion } from "./on-completion";
|
||||
import { TTLCache } from "./utils/cache";
|
||||
import { valueProviders } from "./value-providers";
|
||||
|
||||
export function initConnection(connection: Connection) {
|
||||
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
|
||||
|
||||
let sessionToken: string | undefined;
|
||||
let repos: RepositoryContext[] = [];
|
||||
const cache = new TTLCache();
|
||||
|
||||
let hasWorkspaceFolderCapability = false;
|
||||
let hasDiagnosticRelatedInformationCapability = false;
|
||||
|
||||
// Register remote console logger with language service
|
||||
registerLogger(connection.console);
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
const capabilities = params.capabilities;
|
||||
|
||||
hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders);
|
||||
hasDiagnosticRelatedInformationCapability = !!(
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
||||
);
|
||||
|
||||
const options: InitializationOptions = params.initializationOptions;
|
||||
sessionToken = options.sessionToken;
|
||||
if (options.repos) {
|
||||
repos = options.repos;
|
||||
}
|
||||
|
||||
if (options.logLevel !== undefined) {
|
||||
setLogLevel(options.logLevel);
|
||||
}
|
||||
|
||||
const result: InitializeResult = {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Full,
|
||||
completionProvider: {
|
||||
resolveProvider: false,
|
||||
triggerCharacters: [":", "."]
|
||||
},
|
||||
hoverProvider: true
|
||||
}
|
||||
};
|
||||
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
result.capabilities.workspace = {
|
||||
workspaceFolders: {
|
||||
supported: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
// The content of a text document has changed. This event is emitted
|
||||
// when the text document first opened or when its content has changed.
|
||||
documents.onDidChangeContent(change => {
|
||||
validateTextDocument(change.document);
|
||||
});
|
||||
|
||||
async function validateTextDocument(textDocument: TextDocument): Promise<void> {
|
||||
const repoContext = repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri));
|
||||
const result = await validate(
|
||||
textDocument,
|
||||
valueProviders(sessionToken, repoContext, cache),
|
||||
contextProviders(sessionToken, repoContext, cache)
|
||||
);
|
||||
|
||||
connection.sendDiagnostics({uri: textDocument.uri, diagnostics: result});
|
||||
}
|
||||
|
||||
// This handler provides the initial list of the completion items.
|
||||
connection.onCompletion(async ({position, textDocument}: TextDocumentPositionParams): Promise<CompletionItem[]> => {
|
||||
return await onCompletion(
|
||||
position,
|
||||
documents.get(textDocument.uri)!,
|
||||
sessionToken,
|
||||
repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri)),
|
||||
cache
|
||||
);
|
||||
});
|
||||
|
||||
connection.onHover(async ({position, textDocument}: HoverParams): Promise<Hover | null> => {
|
||||
return hover(documents.get(textDocument.uri)!, position);
|
||||
});
|
||||
|
||||
// Make the text document manager listen on the connection
|
||||
// for open, change and close text document events
|
||||
documents.listen(connection);
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
}
|
||||
@@ -18,13 +18,14 @@ export function contextProviders(
|
||||
auth: sessionToken
|
||||
});
|
||||
|
||||
const getContext = async (name: string) => {
|
||||
const getContext = async (name: string, defaultContext: data.Dictionary | undefined) => {
|
||||
switch (name) {
|
||||
case "secrets":
|
||||
const secrets = await getSecrets(octokit, cache, repo.owner, repo.name);
|
||||
const secretContext = new data.Dictionary();
|
||||
secrets.forEach(secret => secretContext.add(secret.value, secret));
|
||||
return secretContext;
|
||||
|
||||
defaultContext = defaultContext || new data.Dictionary();
|
||||
secrets.forEach(secret => defaultContext!.add(secret.value, new data.StringData("***")));
|
||||
return defaultContext;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -2,8 +2,15 @@ import {StringData} from "@github/actions-expressions/data/string";
|
||||
import {Octokit} from "@octokit/rest";
|
||||
import {TTLCache} from "../utils/cache";
|
||||
|
||||
export function getSecrets(octokit: Octokit, cache: TTLCache, owner: string, name: string): Promise<StringData[]> {
|
||||
return cache.get(`${owner}/${name}/secrets`, undefined, () => fetchSecrets(octokit, owner, name));
|
||||
export async function getSecrets(
|
||||
octokit: Octokit,
|
||||
cache: TTLCache,
|
||||
owner: string,
|
||||
name: string
|
||||
): Promise<StringData[]> {
|
||||
const repoSecrets = await cache.get(`${owner}/${name}/secrets`, undefined, () => fetchSecrets(octokit, owner, name));
|
||||
|
||||
return repoSecrets;
|
||||
}
|
||||
|
||||
async function fetchSecrets(octokit: Octokit, owner: string, name: string): Promise<StringData[]> {
|
||||
|
||||
@@ -1,113 +1,7 @@
|
||||
import {
|
||||
CompletionItem,
|
||||
createConnection,
|
||||
Hover,
|
||||
HoverParams,
|
||||
InitializeParams,
|
||||
InitializeResult,
|
||||
TextDocumentPositionParams,
|
||||
TextDocuments,
|
||||
TextDocumentSyncKind
|
||||
} from "vscode-languageserver/node";
|
||||
import {createConnection} from "vscode-languageserver/node";
|
||||
|
||||
import {hover, registerLogger, setLogLevel, validate} from "@github/actions-languageservice";
|
||||
import {TextDocument} from "vscode-languageserver-textdocument";
|
||||
import {contextProviders} from "./context-providers";
|
||||
import {InitializationOptions, RepositoryContext} from "./initializationOptions";
|
||||
import {onCompletion} from "./on-completion";
|
||||
import {TTLCache} from "./utils/cache";
|
||||
import {valueProviders} from "./value-providers";
|
||||
import {initConnection} from "./connection";
|
||||
|
||||
// By default create node connection
|
||||
const connection = createConnection();
|
||||
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
|
||||
|
||||
let sessionToken: string | undefined;
|
||||
let repos: RepositoryContext[] = [];
|
||||
const cache = new TTLCache();
|
||||
|
||||
let hasWorkspaceFolderCapability = false;
|
||||
let hasDiagnosticRelatedInformationCapability = false;
|
||||
|
||||
// Register remote console logger with language service
|
||||
registerLogger(connection.console);
|
||||
|
||||
connection.onInitialize((params: InitializeParams) => {
|
||||
const capabilities = params.capabilities;
|
||||
|
||||
hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders);
|
||||
hasDiagnosticRelatedInformationCapability = !!(
|
||||
capabilities.textDocument &&
|
||||
capabilities.textDocument.publishDiagnostics &&
|
||||
capabilities.textDocument.publishDiagnostics.relatedInformation
|
||||
);
|
||||
|
||||
const options: InitializationOptions = params.initializationOptions;
|
||||
sessionToken = options.sessionToken;
|
||||
if (options.repos) {
|
||||
repos = options.repos;
|
||||
}
|
||||
|
||||
if (options.logLevel !== undefined) {
|
||||
setLogLevel(options.logLevel);
|
||||
}
|
||||
|
||||
const result: InitializeResult = {
|
||||
capabilities: {
|
||||
textDocumentSync: TextDocumentSyncKind.Full,
|
||||
completionProvider: {
|
||||
resolveProvider: false,
|
||||
triggerCharacters: [":", "."]
|
||||
},
|
||||
hoverProvider: true
|
||||
}
|
||||
};
|
||||
|
||||
if (hasWorkspaceFolderCapability) {
|
||||
result.capabilities.workspace = {
|
||||
workspaceFolders: {
|
||||
supported: true
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
return result;
|
||||
});
|
||||
|
||||
// The content of a text document has changed. This event is emitted
|
||||
// when the text document first opened or when its content has changed.
|
||||
documents.onDidChangeContent(change => {
|
||||
validateTextDocument(change.document);
|
||||
});
|
||||
|
||||
async function validateTextDocument(textDocument: TextDocument): Promise<void> {
|
||||
const repoContext = repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri));
|
||||
const result = await validate(
|
||||
textDocument,
|
||||
valueProviders(sessionToken, repoContext, cache),
|
||||
contextProviders(sessionToken, repoContext, cache)
|
||||
);
|
||||
|
||||
connection.sendDiagnostics({uri: textDocument.uri, diagnostics: result});
|
||||
}
|
||||
|
||||
// This handler provides the initial list of the completion items.
|
||||
connection.onCompletion(async ({position, textDocument}: TextDocumentPositionParams): Promise<CompletionItem[]> => {
|
||||
return await onCompletion(
|
||||
position,
|
||||
documents.get(textDocument.uri)!,
|
||||
sessionToken,
|
||||
repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri)),
|
||||
cache
|
||||
);
|
||||
});
|
||||
|
||||
connection.onHover(async ({position, textDocument}: HoverParams): Promise<Hover | null> => {
|
||||
return hover(documents.get(textDocument.uri)!, position);
|
||||
});
|
||||
|
||||
// Make the text document manager listen on the connection
|
||||
// for open, change and close text document events
|
||||
documents.listen(connection);
|
||||
|
||||
// Listen on the connection
|
||||
connection.listen();
|
||||
initConnection(connection);
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@github/actions-languageservice",
|
||||
"version": "0.1.39",
|
||||
"version": "0.1.41",
|
||||
"description": "Language service for GitHub Actions",
|
||||
"license": "MIT",
|
||||
"type": "module",
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
import {data} from "@github/actions-expressions";
|
||||
import {complete, getExpressionInput} from "./complete";
|
||||
import {ContextProviderConfig} from "./context-providers/config";
|
||||
import {registerLogger} from "./log";
|
||||
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
||||
import {TestLogger} from "./test-utils/logger";
|
||||
|
||||
const contextProviderConfig: ContextProviderConfig = {
|
||||
getContext: async (context: string) => {
|
||||
@@ -11,17 +13,14 @@ const contextProviderConfig: ContextProviderConfig = {
|
||||
key: "event",
|
||||
value: new data.StringData("push")
|
||||
});
|
||||
case "secrets":
|
||||
return new data.Dictionary({
|
||||
key: "DEPLOY_KEY",
|
||||
value: new data.StringData("DEPLOY_KEY")
|
||||
});
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
};
|
||||
|
||||
registerLogger(new TestLogger());
|
||||
|
||||
describe("expressions", () => {
|
||||
it("input extraction", () => {
|
||||
const test = (input: string) => {
|
||||
@@ -146,7 +145,7 @@ jobs:
|
||||
`;
|
||||
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
|
||||
|
||||
expect(result.map(x => x.label)).toEqual(["DEPLOY_KEY"]);
|
||||
expect(result.map(x => x.label)).toEqual(["GITHUB_TOKEN"]);
|
||||
});
|
||||
|
||||
it("needs context only includes referenced jobs", async () => {
|
||||
|
||||
@@ -1,9 +1,13 @@
|
||||
import {TextEdit} from "vscode-languageserver-types";
|
||||
import {complete} from "./complete";
|
||||
import {WorkflowContext} from "./context/workflow-context";
|
||||
import {registerLogger} from "./log";
|
||||
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
||||
import {TestLogger} from "./test-utils/logger";
|
||||
import {ValueProviderConfig, ValueProviderKind} from "./value-providers/config";
|
||||
|
||||
registerLogger(new TestLogger());
|
||||
|
||||
describe("completion", () => {
|
||||
it("runs-on", async () => {
|
||||
const input = "on: push\njobs:\n build:\n runs-on: |";
|
||||
|
||||
@@ -3,7 +3,7 @@ import {Dictionary} from "@github/actions-expressions/data/dictionary";
|
||||
import {ExpressionData, Pair} from "@github/actions-expressions/data/expressiondata";
|
||||
|
||||
export type ContextProviderConfig = {
|
||||
getContext: (name: string) => Promise<data.Dictionary | undefined>;
|
||||
getContext: (name: string, defaultContext: data.Dictionary | undefined) => Promise<data.Dictionary | undefined>;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -20,17 +20,9 @@ export async function getContext(
|
||||
|
||||
const filteredNames = filterContextNames(names, workflowContext);
|
||||
for (const contextName of filteredNames) {
|
||||
let value: ContextValue | undefined;
|
||||
let value = (await getDefaultContext(contextName, workflowContext)) || new data.Dictionary();
|
||||
|
||||
value = await getDefaultContext(contextName, workflowContext);
|
||||
|
||||
if (!value) {
|
||||
value = await config?.getContext(contextName);
|
||||
}
|
||||
|
||||
if (!value) {
|
||||
value = new data.Dictionary();
|
||||
}
|
||||
value = (await config?.getContext(contextName, value)) || value;
|
||||
|
||||
context.add(contextName, value);
|
||||
}
|
||||
@@ -55,6 +47,9 @@ async function getDefaultContext(name: string, workflowContext: WorkflowContext)
|
||||
case "inputs":
|
||||
return getInputsContext(workflowContext);
|
||||
|
||||
case "secrets":
|
||||
return objectToDictionary({GITHUB_TOKEN: "***"});
|
||||
|
||||
case "steps":
|
||||
return getStepsContext(workflowContext);
|
||||
|
||||
|
||||
@@ -0,0 +1,19 @@
|
||||
import {Logger} from "../log";
|
||||
|
||||
export class TestLogger implements Logger {
|
||||
error(message: string): void {
|
||||
throw new Error(`Error: ${message}`);
|
||||
}
|
||||
|
||||
warn(message: string): void {
|
||||
console.warn(message);
|
||||
}
|
||||
|
||||
info(message: string): void {
|
||||
console.info(message);
|
||||
}
|
||||
|
||||
log(message: string): void {
|
||||
console.warn(message);
|
||||
}
|
||||
}
|
||||
@@ -1,7 +1,11 @@
|
||||
import {DiagnosticSeverity} from "vscode-languageserver-types";
|
||||
import {registerLogger} from "./log";
|
||||
import {createDocument} from "./test-utils/document";
|
||||
import {TestLogger} from "./test-utils/logger";
|
||||
import {validate} from "./validate";
|
||||
|
||||
registerLogger(new TestLogger());
|
||||
|
||||
describe("expression validation", () => {
|
||||
it("access invalid context field", async () => {
|
||||
const result = await validate(
|
||||
|
||||
@@ -22,6 +22,7 @@ import {ContextProviderConfig} from "./context-providers/config";
|
||||
import {getContext} from "./context-providers/default";
|
||||
import {getWorkflowContext, WorkflowContext} from "./context/workflow-context";
|
||||
import {AccessError, wrapDictionary} from "./expression-validation/error-dictionary";
|
||||
import {error} from "./log";
|
||||
import {nullTrace} from "./nulltrace";
|
||||
import {getAllowedContext} from "./utils/allowed-context";
|
||||
import {findToken} from "./utils/find-token";
|
||||
@@ -75,8 +76,7 @@ export async function validate(
|
||||
});
|
||||
}
|
||||
} catch (e) {
|
||||
// TODO: Handle error here
|
||||
console.error(e);
|
||||
error(`Unhandled error while validating: ${e}`);
|
||||
}
|
||||
|
||||
return diagnostics;
|
||||
@@ -211,7 +211,7 @@ async function validateExpression(
|
||||
range: mapRange(expression.range)
|
||||
});
|
||||
} else {
|
||||
// Ignore error
|
||||
throw e;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
## Development
|
||||
|
||||
Install dependencies locally, unfortunately via the workspace is not enough to run `webpack-dev-server`. Then
|
||||
|
||||
```bash
|
||||
$ npm start
|
||||
```
|
||||
|
||||
to serve the app at `localhost:8080`.
|
||||
@@ -0,0 +1,35 @@
|
||||
{
|
||||
"name": "browser-playground",
|
||||
"version": "0.1.41",
|
||||
"description": "",
|
||||
"private": true,
|
||||
"main": "index.js",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@github/actions-languageserver": "^0.1.41",
|
||||
"monaco-editor-webpack-plugin": "^7.0.1",
|
||||
"monaco-editor-workers": "^0.34.2",
|
||||
"monaco-languageclient": "^4.0.3",
|
||||
"path-browserify": "^1.0.1",
|
||||
"vscode-languageserver": "^8.0.2",
|
||||
"vscode-languageserver-protocol": "^3.17.2"
|
||||
},
|
||||
"scripts": {
|
||||
"build": "webpack --mode production",
|
||||
"clean": "rimraf dist",
|
||||
"start": "webpack-dev-server --mode development --open",
|
||||
"test": "exit 0",
|
||||
"watch": "webpack --watch --mode development --env esbuild"
|
||||
},
|
||||
"license": "MIT",
|
||||
"devDependencies": {
|
||||
"css-loader": "^6.7.2",
|
||||
"rimraf": "^3.0.2",
|
||||
"style-loader": "^3.3.1",
|
||||
"ts-loader": "^9.4.2",
|
||||
"typescript": "^4.9.4",
|
||||
"webpack": "^5.75.0",
|
||||
"webpack-cli": "^5.0.1",
|
||||
"webpack-dev-server": "^4.11.1"
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>GitHub Actions Language Services</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script defer type="module" src="./index.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div id="container" style="width: 95vw;height: 95vh"></div>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -0,0 +1,70 @@
|
||||
import * as monaco from "monaco-editor";
|
||||
|
||||
import {
|
||||
CloseAction,
|
||||
ErrorAction,
|
||||
MessageTransports,
|
||||
MonacoLanguageClient,
|
||||
MonacoServices,
|
||||
} from "monaco-languageclient";
|
||||
import {
|
||||
BrowserMessageReader,
|
||||
BrowserMessageWriter,
|
||||
} from "vscode-languageserver-protocol/browser.js";
|
||||
|
||||
monaco.editor.create(document.getElementById("container")!, {
|
||||
value: `name: Demo workflow
|
||||
|
||||
on:
|
||||
push:
|
||||
workflow_dispatch:
|
||||
inputs:
|
||||
name:
|
||||
type: string
|
||||
|
||||
jobs:
|
||||
say-hello:
|
||||
runs-on: ubuntu-latest
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- run: echo "Hello \${{ github.event.inputs.name }}"`,
|
||||
language: "yaml",
|
||||
});
|
||||
|
||||
function createLanguageClient(
|
||||
transports: MessageTransports
|
||||
): MonacoLanguageClient {
|
||||
return new MonacoLanguageClient({
|
||||
name: "GitHub Actions Language Client",
|
||||
clientOptions: {
|
||||
// Handle all yaml files as workflows
|
||||
documentSelector: [{ language: "yaml" }],
|
||||
errorHandler: {
|
||||
error: () => ({ action: ErrorAction.Continue }),
|
||||
closed: () => ({ action: CloseAction.DoNotRestart }),
|
||||
},
|
||||
// Custom options for the GitHub Actions language server
|
||||
initializationOptions: {},
|
||||
},
|
||||
connectionProvider: {
|
||||
get: () => Promise.resolve(transports),
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
MonacoServices.install();
|
||||
|
||||
const worker = new Worker(
|
||||
new URL("../service-worker/service-worker.ts", import.meta.url),
|
||||
{
|
||||
type: "module",
|
||||
}
|
||||
);
|
||||
|
||||
const reader = new BrowserMessageReader(worker);
|
||||
const writer = new BrowserMessageWriter(worker);
|
||||
|
||||
const languageClient = createLanguageClient({ reader, writer });
|
||||
languageClient.start();
|
||||
reader.onClose(() => languageClient.stop());
|
||||
@@ -0,0 +1,9 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2022", "DOM"]
|
||||
},
|
||||
"references": [
|
||||
{ "path": "../service-worker" }
|
||||
]
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
import {
|
||||
BrowserMessageReader,
|
||||
BrowserMessageWriter,
|
||||
createConnection,
|
||||
} from "vscode-languageserver/browser.js";
|
||||
|
||||
import { initConnection } from "@github/actions-languageserver/connection";
|
||||
|
||||
const messageReader = new BrowserMessageReader(self);
|
||||
const messageWriter = new BrowserMessageWriter(self);
|
||||
|
||||
const connection = createConnection(messageReader, messageWriter);
|
||||
|
||||
initConnection(connection);
|
||||
@@ -0,0 +1,6 @@
|
||||
{
|
||||
"extends": "../../tsconfig.json",
|
||||
"compilerOptions": {
|
||||
"lib": ["ES2022", "WebWorker"],
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
{
|
||||
"compilerOptions": {
|
||||
"target": "ES2022",
|
||||
"module": "ES2022",
|
||||
"moduleResolution": "Node16",
|
||||
"lib": ["ES2022", "dom"],
|
||||
"esModuleInterop": true,
|
||||
"resolveJsonModule": true,
|
||||
"declaration": true,
|
||||
"declarationMap": true,
|
||||
"sourceMap": true,
|
||||
"inlineSources": false,
|
||||
"stripInternal": true,
|
||||
"strict": true,
|
||||
"strictPropertyInitialization": false,
|
||||
"importHelpers": true,
|
||||
"downlevelIteration": false,
|
||||
"noImplicitReturns": true,
|
||||
"noUnusedParameters": true,
|
||||
"noUnusedLocals": true,
|
||||
// Disallow inconsistently-cased references to the same file
|
||||
"forceConsistentCasingInFileNames": true,
|
||||
"noImplicitOverride": true,
|
||||
"rootDir": "src",
|
||||
"outDir": "dist",
|
||||
"composite": true
|
||||
},
|
||||
}
|
||||
@@ -0,0 +1,59 @@
|
||||
const MonacoWebpackPlugin = require("monaco-editor-webpack-plugin");
|
||||
const path = require("path");
|
||||
|
||||
const editorConfig = {
|
||||
entry: "./src/client/client.ts",
|
||||
devtool: "source-map",
|
||||
output: {
|
||||
path: path.resolve(__dirname, "dist"),
|
||||
filename: "./index.js",
|
||||
},
|
||||
resolve: {
|
||||
extensions: [".ts", ".js"],
|
||||
fallback: {
|
||||
path: require.resolve("path-browserify"),
|
||||
},
|
||||
},
|
||||
module: {
|
||||
rules: [
|
||||
{
|
||||
test: /\.ts$/,
|
||||
exclude: /node_modules/,
|
||||
use: [
|
||||
{
|
||||
loader: "ts-loader",
|
||||
options: {
|
||||
compilerOptions: {
|
||||
sourceMap: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
],
|
||||
},
|
||||
{
|
||||
test: /\.m?js$/,
|
||||
resolve: {
|
||||
fullySpecified: false, // disable the behaviour
|
||||
},
|
||||
},
|
||||
{
|
||||
test: /\.css$/,
|
||||
use: ["style-loader", "css-loader"],
|
||||
},
|
||||
{
|
||||
test: /\.ttf$/,
|
||||
type: "asset/resource",
|
||||
},
|
||||
],
|
||||
},
|
||||
devServer: {
|
||||
static: {
|
||||
directory: path.join(__dirname, "public"),
|
||||
},
|
||||
compress: true,
|
||||
port: 3000,
|
||||
},
|
||||
plugins: [new MonacoWebpackPlugin()],
|
||||
};
|
||||
|
||||
module.exports = [editorConfig]
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
{
|
||||
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
|
||||
"useWorkspaces": true,
|
||||
"version": "0.1.39"
|
||||
"version": "0.1.41"
|
||||
}
|
||||
|
||||
Generated
+4734
-109
File diff suppressed because it is too large
Load Diff
+2
-1
@@ -2,7 +2,8 @@
|
||||
"private": true,
|
||||
"workspaces": [
|
||||
"actions-languageservice",
|
||||
"actions-languageserver"
|
||||
"actions-languageserver",
|
||||
"browser-playground"
|
||||
],
|
||||
"devDependencies": {
|
||||
"lerna": "^6.0.3"
|
||||
|
||||
Reference in New Issue
Block a user