Merge branch 'main' into joshmgross/workflow_call-validation

This commit is contained in:
Josh Gross
2023-02-01 10:44:24 -05:00
38 changed files with 510 additions and 344 deletions
+3 -2
View File
@@ -12,14 +12,15 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Use Node.js 16.x
- name: Use Node.js 16.15
uses: actions/setup-node@v3
with:
node-version: 16.x
node-version: 16.15
cache: 'npm'
registry-url: 'https://npm.pkg.github.com'
- run: npm ci
env:
NODE_AUTH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- run: npm run format-check -ws
- run: npm run build -ws
- run: npm test -ws
+1
View File
@@ -3,3 +3,4 @@ dist
*.md
*.js
*.json
*.d.ts
+3 -3
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-expressions",
"version": "0.1.100",
"version": "0.1.109",
"license": "MIT",
"type": "module",
"source": "./src/index.ts",
@@ -37,7 +37,7 @@
"watch": "tsc --build tsconfig.build.json --watch"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
},
"files": [
"dist/**/*"
@@ -45,7 +45,7 @@
"devDependencies": {
"@types/jest": "^29.0.3",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.7.4"
+6 -6
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-languageserver",
"version": "0.1.100",
"version": "0.1.109",
"description": "Language server for GitHub Actions",
"license": "MIT",
"type": "module",
@@ -38,15 +38,15 @@
"watch": "tsc --build tsconfig.build.json --watch"
},
"dependencies": {
"@github/actions-languageservice": "^0.1.100",
"@github/actions-workflow-parser": "^0.1.100",
"@octokit/rest": "^19.0.5",
"@github/actions-languageservice": "^0.1.109",
"@github/actions-workflow-parser": "^0.1.109",
"@octokit/rest": "^19.0.7",
"vscode-languageserver": "^8.0.2",
"vscode-languageserver-textdocument": "^1.0.7",
"yaml": "^2.1.3"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
},
"files": [
"dist/**/*"
@@ -55,7 +55,7 @@
"@types/jest": "^29.0.3",
"fetch-mock": "^9.11.0",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4"
+8
View File
@@ -0,0 +1,8 @@
import {Octokit} from "@octokit/rest";
export function getClient(token: string, userAgent?: string): Octokit {
return new Octokit({
auth: token,
userAgent: userAgent || `GitHub Actions Language Server`
});
}
+16 -13
View File
@@ -16,19 +16,20 @@ import {
TextDocumentSyncKind
} from "vscode-languageserver";
import {TextDocument} from "vscode-languageserver-textdocument";
import {getClient} from "./client";
import {Commands} from "./commands";
import {contextProviders} from "./context-providers";
import {descriptionProvider} from "./description-provider";
import {InitializationOptions, RepositoryContext} from "./initializationOptions";
import {onCompletion} from "./on-completion";
import {TTLCache} from "./utils/cache";
import {valueProviders} from "./value-providers";
import {getActionInputs} from "./value-providers/action-inputs";
import {Commands} from "./commands";
import {descriptionProvider} from "./description-provider";
export function initConnection(connection: Connection) {
const documents: TextDocuments<TextDocument> = new TextDocuments(TextDocument);
let sessionToken: string | undefined;
let client: Octokit | undefined;
let repos: RepositoryContext[] = [];
const cache = new TTLCache();
@@ -49,7 +50,11 @@ export function initConnection(connection: Connection) {
);
const options: InitializationOptions = params.initializationOptions;
sessionToken = options.sessionToken;
if (options.sessionToken) {
client = getClient(options.sessionToken, options.userAgent);
}
if (options.repos) {
repos = options.repos;
}
@@ -93,15 +98,13 @@ export function initConnection(connection: Connection) {
const repoContext = repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri));
const config: ValidationConfig = {
valueProviderConfig: valueProviders(sessionToken, repoContext, cache),
contextProviderConfig: contextProviders(sessionToken, repoContext, cache),
valueProviderConfig: valueProviders(client, repoContext, cache),
contextProviderConfig: contextProviders(client, repoContext, cache),
getActionInputs: async action => {
if (sessionToken) {
const octokit = new Octokit({
auth: sessionToken
});
return await getActionInputs(octokit, cache, action);
if (client) {
return await getActionInputs(client, cache, action);
}
return undefined;
}
};
@@ -114,7 +117,7 @@ export function initConnection(connection: Connection) {
return await onCompletion(
position,
documents.get(textDocument.uri)!,
sessionToken,
client,
repos.find(repo => textDocument.uri.startsWith(repo.workspaceUri)),
cache
);
@@ -122,7 +125,7 @@ export function initConnection(connection: Connection) {
connection.onHover(async ({position, textDocument}: HoverParams): Promise<Hover | null> => {
return hover(documents.get(textDocument.uri)!, position, {
descriptionProvider: descriptionProvider(sessionToken, cache)
descriptionProvider: descriptionProvider(client, cache)
});
});
@@ -9,18 +9,14 @@ import {RepositoryContext} from "./initializationOptions";
import {TTLCache} from "./utils/cache";
export function contextProviders(
sessionToken: string | undefined,
client: Octokit | undefined,
repo: RepositoryContext | undefined,
cache: TTLCache
): ContextProviderConfig {
if (!repo || !sessionToken) {
if (!repo || !client) {
return {getContext: (_: string) => Promise.resolve(undefined)};
}
const octokit = new Octokit({
auth: sessionToken
});
const getContext = async (
name: string,
defaultContext: DescriptionDictionary | undefined,
@@ -28,11 +24,11 @@ export function contextProviders(
) => {
switch (name) {
case "secrets":
return await getSecrets(workflowContext, octokit, cache, repo, defaultContext);
return await getSecrets(workflowContext, client, cache, repo, defaultContext);
case "vars":
return await getVariables(workflowContext, octokit, cache, repo, defaultContext);
return await getVariables(workflowContext, client, cache, repo, defaultContext);
case "steps":
return await getStepsContext(octokit, cache, defaultContext, workflowContext);
return await getStepsContext(client, cache, defaultContext, workflowContext);
}
};
@@ -41,6 +41,15 @@ export async function getSecrets(
}
>();
secrets.orgSecrets.forEach(secret =>
secretsMap.set(secret.value.toLowerCase(), {
key: secret.value,
value: new data.StringData("***"),
description: "Organization secret"
})
);
// Override org secrets with repo secrets
secrets.repoSecrets.forEach(secret =>
secretsMap.set(secret.value.toLowerCase(), {
key: secret.value,
@@ -76,6 +85,7 @@ async function getRemoteSecrets(
): Promise<{
repoSecrets: StringData[];
environmentSecrets: StringData[];
orgSecrets: StringData[];
}> {
return {
repoSecrets: await cache.get(`${repo.owner}/${repo.name}/secrets`, undefined, () =>
@@ -86,18 +96,22 @@ async function getRemoteSecrets(
(await cache.get(`${repo.owner}/${repo.name}/secrets/environment/${environmentName}`, undefined, () =>
fetchEnvironmentSecrets(octokit, repo.id, environmentName)
))) ||
[]
[],
orgSecrets: await cache.get(`${repo.owner}/secrets`, undefined, () => fetchOrganizationSecrets(octokit, repo))
};
}
async function fetchSecrets(octokit: Octokit, owner: string, name: string): Promise<StringData[]> {
try {
const response = await octokit.actions.listRepoSecrets({
owner,
repo: name
});
return response.data.secrets.map(secret => new StringData(secret.name));
return await octokit.paginate(
octokit.actions.listRepoSecrets,
{
owner,
repo: name,
per_page: 100
},
response => response.data.map(secret => new StringData(secret.name))
);
} catch (e) {
console.log("Failure to retrieve secrets: ", e);
}
@@ -111,15 +125,37 @@ async function fetchEnvironmentSecrets(
environmentName: string
): Promise<StringData[]> {
try {
const response = await octokit.actions.listEnvironmentSecrets({
repository_id: repositoryId,
environment_name: environmentName
});
return response.data.secrets.map(secret => new StringData(secret.name));
return await octokit.paginate(
octokit.actions.listEnvironmentSecrets,
{
repository_id: repositoryId,
environment_name: environmentName,
per_page: 100
},
response => response.data.map(secret => new StringData(secret.name))
);
} catch (e) {
console.log("Failure to retrieve environment secrets: ", e);
}
return [];
}
async function fetchOrganizationSecrets(octokit: Octokit, repo: RepositoryContext): Promise<StringData[]> {
if (!repo.organizationOwned) {
return [];
}
try {
const secrets: {name: string}[] = await octokit.paginate("GET /repos/{owner}/{repo}/actions/organization-secrets", {
owner: repo.owner,
repo: repo.name,
per_page: 100
});
return secrets.map(secret => new StringData(secret.name));
} catch (e) {
console.log("Failure to retrieve organization secrets: ", e);
}
return [];
}
@@ -42,6 +42,15 @@ export async function getVariables(
}
>();
variables.organizationVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
value: new data.StringData(variable.value.coerceString()),
description: `${variable.value.coerceString()} - Organization variable`
})
);
// Override org variables with repo variables
variables.repoVariables.forEach(variable =>
variablesMap.set(variable.key.toLowerCase(), {
key: variable.key,
@@ -77,6 +86,7 @@ export async function getRemoteVariables(
): Promise<{
repoVariables: Pair[];
environmentVariables: Pair[];
organizationVariables: Pair[];
}> {
// Repo variables
return {
@@ -88,25 +98,27 @@ export async function getRemoteVariables(
(await cache.get(`${repo.owner}/${repo.name}/vars/environment/${environmentName}`, undefined, () =>
fetchEnvironmentVariables(octokit, repo.id, environmentName)
))) ||
[]
[],
organizationVariables: await cache.get(`${repo.owner}/vars`, undefined, () =>
fetchOrganizationVariables(octokit, repo)
)
};
}
async function fetchVariables(octokit: Octokit, owner: string, name: string): Promise<Pair[]> {
try {
const response = (await octokit.paginate("GET /repos/{owner}/{repo}/actions/variables{?per_page}", {
owner: owner,
repo: name
})) as {
name: string;
value: string;
created_at: string;
updated_at: string;
}[];
return response.map(variable => {
return {key: variable.name, value: new StringData(variable.value)};
});
return await octokit.paginate(
octokit.actions.listRepoVariables,
{
owner: owner,
repo: name,
per_page: 100
},
response =>
response.data.map(variable => {
return {key: variable.name, value: new StringData(variable.value)};
})
);
} catch (e) {
console.log("Failure to retrieve variables: ", e);
}
@@ -120,25 +132,45 @@ async function fetchEnvironmentVariables(
environmentName: string
): Promise<Pair[]> {
try {
const response = (await octokit.paginate(
"GET /repositories/{repository_id}/environments/{environment_name}/variables{?per_page}",
return await octokit.paginate(
octokit.actions.listEnvironmentVariables,
{
repository_id: repositoryId,
environment_name: environmentName
}
)) as {
name: string;
value: string;
created_at: string;
updated_at: string;
}[];
return response.map(variable => {
return {key: variable.name, value: new StringData(variable.value)};
});
environment_name: environmentName,
per_page: 100
},
response =>
response.data.map(variable => {
return {key: variable.name, value: new StringData(variable.value)};
})
);
} catch (e) {
console.log("Failure to retrieve environment variables: ", e);
}
return [];
}
async function fetchOrganizationVariables(octokit: Octokit, repo: RepositoryContext): Promise<Pair[]> {
if (!repo.organizationOwned) {
return [];
}
try {
const variables: {name: string; value: string}[] = await octokit.paginate(
"GET /repos/{owner}/{repo}/actions/organization-variables",
{
owner: repo.owner,
repo: repo.name,
per_page: 100
}
);
return variables.map(variable => {
return {key: variable.name, value: new StringData(variable.value)};
});
} catch (e) {
console.log("Failure to retrieve organization variables: ", e);
}
return [];
}
@@ -1,22 +1,17 @@
import {DescriptionProvider} from "@github/actions-languageservice/hover";
import {Octokit} from "@octokit/rest";
import {TTLCache} from "./utils/cache";
import {getActionInputDescription} from "./description-providers/action-input";
import {TTLCache} from "./utils/cache";
export function descriptionProvider(sessionToken: string | undefined, cache: TTLCache): DescriptionProvider {
const octokit =
sessionToken &&
new Octokit({
auth: sessionToken
});
export function descriptionProvider(client: Octokit | undefined, cache: TTLCache): DescriptionProvider {
const getDescription: DescriptionProvider["getDescription"] = async (context, token, path) => {
if (!octokit) {
if (!client) {
return undefined;
}
const parent = path[path.length - 1];
if (context.step && parent.definition?.key === "step-with") {
return await getActionInputDescription(octokit, cache, context.step, token);
return await getActionInputDescription(client, cache, context.step, token);
}
};
@@ -9,6 +9,11 @@ export interface InitializationOptions {
*/
sessionToken?: string;
/**
* Optional user agent to use when making calls to github.com
*/
userAgent?: string;
/**
* List of repositories that the language server should be aware of
*/
@@ -31,6 +36,11 @@ export interface RepositoryContext {
*/
owner: string;
/**
* Indicates if the repository is owned by an organization
*/
organizationOwned: boolean;
/**
* Repository name
*/
+4 -3
View File
@@ -1,4 +1,5 @@
import {complete} from "@github/actions-languageservice/complete";
import {Octokit} from "@octokit/rest";
import {CompletionItem, Position} from "vscode-languageserver";
import {TextDocument} from "vscode-languageserver-textdocument";
import {contextProviders} from "./context-providers";
@@ -9,14 +10,14 @@ import {valueProviders} from "./value-providers";
export async function onCompletion(
position: Position,
document: TextDocument,
sessionToken: string | undefined,
client: Octokit | undefined,
repoContext: RepositoryContext | undefined,
cache: TTLCache
): Promise<CompletionItem[]> {
return await complete(
document,
position,
repoContext && valueProviders(sessionToken, repoContext, cache),
repoContext && contextProviders(sessionToken, repoContext, cache)
repoContext && valueProviders(client, repoContext, cache),
repoContext && contextProviders(client, repoContext, cache)
);
}
+6 -10
View File
@@ -9,34 +9,30 @@ import {getEnvironments} from "./value-providers/job-environment";
import {getRunnerLabels} from "./value-providers/runs-on";
export function valueProviders(
sessionToken: string | undefined,
client: Octokit | undefined,
repo: RepositoryContext | undefined,
cache: TTLCache
): ValueProviderConfig {
if (!repo || !sessionToken) {
if (!repo || !client) {
return {};
}
const octokit = new Octokit({
auth: sessionToken
});
return {
"job-environment": {
kind: ValueProviderKind.AllowedValues,
get: (_: WorkflowContext) => getEnvironments(octokit, cache, repo.owner, repo.name)
get: (_: WorkflowContext) => getEnvironments(client, cache, repo.owner, repo.name)
},
"job-environment-name": {
kind: ValueProviderKind.AllowedValues,
get: (_: WorkflowContext) => getEnvironments(octokit, cache, repo.owner, repo.name)
get: (_: WorkflowContext) => getEnvironments(client, cache, repo.owner, repo.name)
},
"runs-on": {
kind: ValueProviderKind.SuggestedValues,
get: (_: WorkflowContext) => getRunnerLabels(octokit, cache, repo.owner, repo.name)
get: (_: WorkflowContext) => getRunnerLabels(client, cache, repo.owner, repo.name)
},
"step-with": {
kind: ValueProviderKind.AllowedValues,
get: (context: WorkflowContext) => getActionInputValues(octokit, cache, context)
get: (context: WorkflowContext) => getActionInputValues(client, cache, context)
}
};
}
@@ -2,6 +2,8 @@ import {Value} from "@github/actions-languageservice/value-providers/config";
import {Octokit} from "@octokit/rest";
import {TTLCache} from "../utils/cache";
// Limitation: getRunnerLabels returns default hosted labels and labels for repository self-hosted runners.
// It doesn't return labels for organization runners visible to the repository.
export async function getRunnerLabels(client: Octokit, cache: TTLCache, owner: string, name: string): Promise<Value[]> {
const defaultLabels = [
"ubuntu-latest",
@@ -33,14 +35,17 @@ export async function getRunnerLabels(client: Octokit, cache: TTLCache, owner: s
async function fetchRunnerLabels(client: Octokit, owner: string, name: string): Promise<Set<string>> {
const labels = new Set<string>();
try {
const response = await client.actions.listSelfHostedRunnersForRepo({
const itor = client.paginate.iterator(client.actions.listSelfHostedRunnersForRepo, {
owner,
repo: name
repo: name,
per_page: 100
});
for (const runner of response.data.runners) {
for (const label of runner.labels) {
labels.add(label.name);
for await (const response of itor) {
for (const runner of response.data) {
for (const label of runner.labels) {
labels.add(label.name);
}
}
}
} catch (e) {
+2 -1
View File
@@ -8,7 +8,8 @@
"sourceMap": true,
"strict": true,
"moduleResolution": "node",
"lib": ["es6", "webworker"]
"lib": ["es6", "webworker"],
"resolveJsonModule": true
},
"watchOptions": {
"watchFile": "useFsEvents",
+5 -5
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-languageservice",
"version": "0.1.100",
"version": "0.1.109",
"description": "Language service for GitHub Actions",
"license": "MIT",
"type": "module",
@@ -38,14 +38,14 @@
"watch": "tsc --build tsconfig.build.json --watch"
},
"dependencies": {
"@github/actions-expressions": "^0.1.100",
"@github/actions-workflow-parser": "^0.1.100",
"@github/actions-expressions": "^0.1.109",
"@github/actions-workflow-parser": "^0.1.109",
"vscode-languageserver-textdocument": "^1.0.7",
"vscode-languageserver-types": "^3.17.2",
"yaml": "^2.1.1"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
},
"files": [
"dist/**/*"
@@ -54,7 +54,7 @@
"devDependencies": {
"@types/jest": "^29.0.3",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4"
@@ -255,6 +255,13 @@ jobs:
expect(result.map(x => x.label)).toEqual(["event"]);
});
it("auto-complete partial", async () => {
const input = "run-name: ${{ github.ev| }}";
const result = await complete(...getPositionFromCursor(input), undefined, contextProviderConfig);
expect(result.map(x => x.label)).toEqual(["event"]);
});
it("using default context provider", async () => {
const input =
"on: push\njobs:\n build:\n runs-on: ubuntu-latest\n environment:\n url: ${{ runner.| }}\n steps:\n - run: echo";
+62 -29
View File
@@ -1,6 +1,12 @@
import {complete as completeExpression} from "@github/actions-expressions";
import {DescriptionDictionary, complete as completeExpression} from "@github/actions-expressions";
import {CompletionItem as ExpressionCompletionItem} from "@github/actions-expressions/completion";
import {convertWorkflowTemplate, isSequence, isString, parseWorkflow} from "@github/actions-workflow-parser";
import {
convertWorkflowTemplate,
isBasicExpression,
isSequence,
isString,
parseWorkflow
} from "@github/actions-workflow-parser";
import {ErrorPolicy} from "@github/actions-workflow-parser/model/convert";
import {DefinitionType} from "@github/actions-workflow-parser/templates/schema/definition-type";
import {StringDefinition} from "@github/actions-workflow-parser/templates/schema/string-definition";
@@ -24,6 +30,7 @@ import {transform} from "./utils/transform";
import {Value, ValueProviderConfig} from "./value-providers/config";
import {defaultValueProviders} from "./value-providers/default";
import {definitionValues} from "./value-providers/definition";
import {TokenRange} from "@github/actions-workflow-parser/templates/tokens/token-range";
export function getExpressionInput(input: string, pos: number): string {
// Find start marker around the cursor position
@@ -71,37 +78,14 @@ export async function complete(
// If we are inside an expression, take a different code-path. The workflow parser does not correctly create
// expression nodes for invalid expressions and during editing expressions are invalid most of the time.
if (token) {
const isExpression =
token.definition?.definitionType === DefinitionType.String && (token.definition as StringDefinition).isExpression;
const containsExpression = isString(token) && token.value.indexOf(OPEN_EXPRESSION) >= 0;
if (isString(token) && (isExpression || containsExpression)) {
const currentInput = token.source || token.value;
// Transform the overall position into a node relative position
let relCharPos: number = 0;
const range = mapRange(token.range!);
if (range.start.line !== range.end.line) {
const lines = currentInput.split("\n");
const lineDiff = newPos.line - range.start.line - 1;
const linesBeforeCusor = lines.slice(0, lineDiff);
relCharPos = linesBeforeCusor.join("\n").length + newPos.character + 1;
} else {
relCharPos = newPos.character - range.start.character;
}
const expressionInput = (getExpressionInput(currentInput, relCharPos) || "").trim();
const isStringExpressionToken = isStringExpression(token);
const isBasicExpressionToken = isBasicExpression(token) && token.isExpression;
if (isStringExpressionToken || isBasicExpressionToken) {
const allowedContext = token.definitionInfo?.allowedContext || [];
const context = await getContext(allowedContext, contextProviderConfig, workflowContext, Mode.Completion);
try {
return completeExpression(expressionInput, context, [], validatorFunctions).map(item =>
mapExpressionCompletionItem(item, currentInput[relCharPos])
);
} catch (e: any) {
error(`Error while completing expression: '${e?.message || "<no details>"}'`);
return [];
}
return getExpressionCompletionItems(token, context, newPos);
}
}
@@ -216,6 +200,35 @@ export function getExistingValues(token: TemplateToken | null, parent: TemplateT
}
}
function getExpressionCompletionItems(
token: TemplateToken,
context: DescriptionDictionary,
pos: Position
): CompletionItem[] {
let expressionInput = "";
let currentInput = "";
let relCharPos: number = 0;
if (isBasicExpression(token)) {
expressionInput = currentInput = token.expression;
relCharPos = getRelCharPos(token.range!, expressionInput, pos);
} else {
const stringToken = token.assertString("Expected string token for expression completion");
currentInput = stringToken.source || stringToken.value;
relCharPos = getRelCharPos(stringToken.range!, currentInput, pos);
expressionInput = (getExpressionInput(currentInput, relCharPos) || "").trim();
}
try {
return completeExpression(expressionInput, context, [], validatorFunctions).map(item =>
mapExpressionCompletionItem(item, currentInput[relCharPos])
);
} catch (e: any) {
error(`Error while completing expression: '${e?.message || "<no details>"}'`);
return [];
}
}
function filterAndSortCompletionOptions(options: Value[], existingValues?: Set<string>) {
options = options.filter(x => !existingValues?.has(x.label));
options.sort((a, b) => a.label.localeCompare(b.label));
@@ -239,3 +252,23 @@ function mapExpressionCompletionItem(item: ExpressionCompletionItem, charAfterPo
kind: item.function ? CompletionItemKind.Function : CompletionItemKind.Variable
};
}
function getRelCharPos(tokenRange: TokenRange, currentInput: string, pos: Position): number {
// Transform the overall position into a node relative position
const range = mapRange(tokenRange);
if (range.start.line !== range.end.line) {
const lines = currentInput.split("\n");
const lineDiff = pos.line - range.start.line - 1;
const linesBeforeCusor = lines.slice(0, lineDiff);
return linesBeforeCusor.join("\n").length + pos.character + 1;
} else {
return pos.character - range.start.character;
}
}
function isStringExpression(token: TemplateToken): boolean {
const isExpression =
token.definition?.definitionType === DefinitionType.String && (token.definition as StringDefinition).isExpression;
const containsExpression = isString(token) && token.value.indexOf(OPEN_EXPRESSION) >= 0;
return isExpression || containsExpression;
}
@@ -1,4 +1,4 @@
import descriptions from "./descriptions.json";
import descriptions from "./descriptions.json" assert {type: "json"};
export const RootContext = "root";
@@ -1,55 +1,55 @@
import check_run from "./check_run.json";
import check_suite from "./check_suite.json";
import commit_comment from "./commit_comment.json";
import content_reference from "./content_reference.json";
import create from "./create.json";
import deletePayload from "./delete.json";
import deploy_key from "./deploy_key.json";
import deployment from "./deployment.json";
import deployment_status from "./deployment_status.json";
import fork from "./fork.json";
import github_app_authorization from "./github_app_authorization.json";
import gollum from "./gollum.json";
import installation from "./installation.json";
import installation_repositories from "./installation_repositories.json";
import issue_comment from "./issue_comment.json";
import issues from "./issues.json";
import label from "./label.json";
import marketplace_purchase from "./marketplace_purchase.json";
import member from "./member.json";
import membership from "./membership.json";
import merge_group from "./merge_group.json";
import meta from "./meta.json";
import milestone from "./milestone.json";
import org_block from "./org_block.json";
import organization from "./organization.json";
import packagePayload from "./package_payload.json";
import page_build from "./page_build.json";
import ping from "./ping.json";
import project from "./project.json";
import project_card from "./project_card.json";
import project_column from "./project_column.json";
import publicPayload from "./public.json";
import pull_request from "./pull_request.json";
import pull_request_review from "./pull_request_review.json";
import pull_request_review_comment from "./pull_request_review_comment.json";
import push from "./push.json";
import release from "./release.json";
import repository from "./repository.json";
import repository_dispatch from "./repository_dispatch.json";
import repository_import from "./repository_import.json";
import repository_vulnerability_alert from "./repository_vulnerability_alert.json";
import schedule from "./schedule.json";
import security_advisory from "./security_advisory.json";
import sponsorship from "./sponsorship.json";
import star from "./star.json";
import status from "./status.json";
import team from "./team.json";
import team_add from "./team_add.json";
import watch from "./watch.json";
import workflow_call from "./workflow_call.json";
import workflow_dispatch from "./workflow_dispatch.json";
import workflow_run from "./workflow_run.json";
import check_run from "./check_run.json" assert {type: "json"};
import check_suite from "./check_suite.json" assert {type: "json"};
import commit_comment from "./commit_comment.json" assert {type: "json"};
import content_reference from "./content_reference.json" assert {type: "json"};
import create from "./create.json" assert {type: "json"};
import deletePayload from "./delete.json" assert {type: "json"};
import deploy_key from "./deploy_key.json" assert {type: "json"};
import deployment from "./deployment.json" assert {type: "json"};
import deployment_status from "./deployment_status.json" assert {type: "json"};
import fork from "./fork.json" assert {type: "json"};
import github_app_authorization from "./github_app_authorization.json" assert {type: "json"};
import gollum from "./gollum.json" assert {type: "json"};
import installation from "./installation.json" assert {type: "json"};
import installation_repositories from "./installation_repositories.json" assert {type: "json"};
import issue_comment from "./issue_comment.json" assert {type: "json"};
import issues from "./issues.json" assert {type: "json"};
import label from "./label.json" assert {type: "json"};
import marketplace_purchase from "./marketplace_purchase.json" assert {type: "json"};
import member from "./member.json" assert {type: "json"};
import membership from "./membership.json" assert {type: "json"};
import merge_group from "./merge_group.json" assert {type: "json"};
import meta from "./meta.json" assert {type: "json"};
import milestone from "./milestone.json" assert {type: "json"};
import org_block from "./org_block.json" assert {type: "json"};
import organization from "./organization.json" assert {type: "json"};
import packagePayload from "./package_payload.json" assert {type: "json"};
import page_build from "./page_build.json" assert {type: "json"};
import ping from "./ping.json" assert {type: "json"};
import project from "./project.json" assert {type: "json"};
import project_card from "./project_card.json" assert {type: "json"};
import project_column from "./project_column.json" assert {type: "json"};
import publicPayload from "./public.json" assert {type: "json"};
import pull_request from "./pull_request.json" assert {type: "json"};
import pull_request_review from "./pull_request_review.json" assert {type: "json"};
import pull_request_review_comment from "./pull_request_review_comment.json" assert {type: "json"};
import push from "./push.json" assert {type: "json"};
import release from "./release.json" assert {type: "json"};
import repository from "./repository.json" assert {type: "json"};
import repository_dispatch from "./repository_dispatch.json" assert {type: "json"};
import repository_import from "./repository_import.json" assert {type: "json"};
import repository_vulnerability_alert from "./repository_vulnerability_alert.json" assert {type: "json"};
import schedule from "./schedule.json" assert {type: "json"};
import security_advisory from "./security_advisory.json" assert {type: "json"};
import sponsorship from "./sponsorship.json" assert {type: "json"};
import star from "./star.json" assert {type: "json"};
import status from "./status.json" assert {type: "json"};
import team from "./team.json" assert {type: "json"};
import team_add from "./team_add.json" assert {type: "json"};
import watch from "./watch.json" assert {type: "json"};
import workflow_call from "./workflow_call.json" assert {type: "json"};
import workflow_dispatch from "./workflow_dispatch.json" assert {type: "json"};
import workflow_run from "./workflow_run.json" assert {type: "json"};
export const eventPayloads: {[key: string]: Object} = {
check_run,
+13 -6
View File
@@ -17,7 +17,7 @@ function testHoverConfig(tokenValue: string, tokenKey: string, description?: str
return description;
}
} satisfies DescriptionProvider
} satisfies HoverConfig
} satisfies HoverConfig;
}
describe("hover", () => {
@@ -146,7 +146,8 @@ jobs:
expect(result).not.toBeUndefined();
// The `ref` is a `string` definition and inherits the context from `step-with`
const expected = "**Context:** github, inputs, vars, needs, strategy, matrix, secrets, steps, job, runner, env, hashFiles(1,255)"
const expected =
"**Context:** github, inputs, vars, needs, strategy, matrix, secrets, steps, job, runner, env, hashFiles(1,255)";
expect(result?.contents).toEqual(expected);
});
});
@@ -164,11 +165,15 @@ jobs:
ref|: main
`;
const result = await hover(...getPositionFromCursor(input), testHoverConfig("ref", "string", "The branch, tag or SHA to checkout."));
const result = await hover(
...getPositionFromCursor(input),
testHoverConfig("ref", "string", "The branch, tag or SHA to checkout.")
);
expect(result).not.toBeUndefined();
const expected = "The branch, tag or SHA to checkout.\n\n" +
"**Context:** github, inputs, vars, needs, strategy, matrix, secrets, steps, job, runner, env, hashFiles(1,255)"
const expected =
"The branch, tag or SHA to checkout.\n\n" +
"**Context:** github, inputs, vars, needs, strategy, matrix, secrets, steps, job, runner, env, hashFiles(1,255)";
expect(result?.contents).toEqual(expected);
});
@@ -184,6 +189,8 @@ jobs:
const result = await hover(...getPositionFromCursor(input), testHoverConfig("uses", "non-empty-string", undefined));
expect(result).not.toBeUndefined();
expect(result?.contents).toEqual("Selects an action to run as part of a step in your job. An action is a reusable unit of code. You can use an action defined in the same repository as the workflow, a public repository, or in a published Docker container image.");
expect(result?.contents).toEqual(
"Selects an action to run as part of a step in your job. An action is a reusable unit of code. You can use an action defined in the same repository as the workflow, a public repository, or in a published Docker container image."
);
});
});
+4 -2
View File
@@ -39,7 +39,7 @@ export async function hover(document: TextDocument, position: Position, config?:
info(`Calculating hover for token with definition ${token.definition.key}`);
if (tokenResult.parent && isCronMappingValue(tokenResult)) {
const tokenValue = (token as StringToken).value
const tokenValue = (token as StringToken).value;
let description = getCronDescription(tokenValue);
if (description) {
return {
@@ -82,7 +82,9 @@ async function getDescription(
}
function isCronMappingValue(tokenResult: TokenResult): boolean {
return tokenResult.parent?.definition?.key === "cron-mapping" &&
return (
tokenResult.parent?.definition?.key === "cron-mapping" &&
isString(tokenResult.token!) &&
tokenResult.token.value !== "cron"
);
}
@@ -141,13 +141,16 @@ function posInToken(pos: Position, token: TemplateToken): boolean {
const tokenChar = pos.character + 1;
// Check lines
if (r.start[0] > tokenLine || tokenLine > r.end[0]) {
if (r.start.line > tokenLine || tokenLine > r.end.line) {
return false;
}
// Position is within the token lines. Check character/column if pos line matches
// start or end
if ((r.start[0] === tokenLine && tokenChar < r.start[1]) || (r.end[0] === tokenLine && tokenChar > r.end[1])) {
if (
(r.start.line === tokenLine && tokenChar < r.start.column) ||
(r.end.line === tokenLine && tokenChar > r.end.column)
) {
return false;
}
@@ -163,14 +166,14 @@ function onSameLine(pos: Position, key: TemplateToken, value: TemplateToken): bo
return false;
}
if (value.range.start[0] !== value.range.end[0]) {
if (value.range.start.line !== value.range.end.line) {
// Token occupies multiple lines, can't be an empty node
return false;
}
// TokenRange is one-based, Position is zero-based
const posLine = pos.line + 1;
if (posLine != value.range.start[0]) {
if (posLine != value.range.start.line) {
return false;
}
+2 -2
View File
@@ -23,7 +23,7 @@ export function mapRange(range: TokenRange | undefined): Range {
export function mapPosition(position: TokenPosition): Position {
return {
line: position[0] - 1,
character: position[1] - 1
line: position.line - 1,
character: position.column - 1
};
}
+2 -30
View File
@@ -73,21 +73,7 @@ jobs:
{valueProviderConfig: defaultValueProviders}
);
expect(result.length).toBe(1);
expect(result[0]).toEqual({
message: "Value 'does-not-exist' might not be valid",
severity: DiagnosticSeverity.Warning,
range: {
end: {
character: 27,
line: 3
},
start: {
character: 13,
line: 3
}
}
} as Diagnostic);
expect(result.length).toBe(0);
});
it("value in sequence not returned by value provider", async () => {
@@ -106,21 +92,7 @@ jobs:
{valueProviderConfig: defaultValueProviders}
);
expect(result.length).toBe(1);
expect(result[0]).toEqual({
message: "Value 'does-not-exist' might not be valid",
severity: DiagnosticSeverity.Warning,
range: {
end: {
character: 20,
line: 5
},
start: {
character: 6,
line: 5
}
}
} as Diagnostic);
expect(result.length).toBe(0);
});
it("single value not returned by allowed value provider", async () => {
+3 -9
View File
@@ -150,13 +150,7 @@ function invalidValue(diagnostics: Diagnostic[], token: StringToken, kind: Value
});
break;
case ValueProviderKind.SuggestedValues:
diagnostics.push({
message: `Value '${token.value}' might not be valid`,
severity: DiagnosticSeverity.Warning,
range: mapRange(token.range)
});
break;
// no messages for SuggestedValues
}
}
@@ -168,8 +162,8 @@ function getProviderContext(
): WorkflowContext {
const {parent, path} = findToken(
{
line: token.range!.start[0] - 1,
character: token.range!.start[1] - 1
line: token.range!.start.line - 1,
character: token.range!.start.column - 1
},
root
);
+4 -4
View File
@@ -1,6 +1,6 @@
{
"name": "@github/actions-workflow-parser",
"version": "0.1.100",
"version": "0.1.109",
"license": "MIT",
"type": "module",
"source": "./src/index.ts",
@@ -40,12 +40,12 @@
"watch": "tsc --build tsconfig.build.json --watch"
},
"dependencies": {
"@github/actions-expressions": "^0.1.100",
"@github/actions-expressions": "^0.1.109",
"cronstrue": "^2.21.0",
"yaml": "^2.0.0-8"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
},
"files": [
"dist/**/*"
@@ -56,7 +56,7 @@
"@typescript-eslint/parser": "^5.40.0",
"eslint": "7.32.0",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4"
@@ -85,15 +85,15 @@ jobs:
[
"${{ github.event_name }}",
{
start: [7, 16],
end: [7, 40]
start: {line: 7, column: 16},
end: {line: 7, column: 40}
}
],
[
"${{ github.ref }}",
{
start: [8, 24],
end: [8, 41]
start: {line: 8, column: 24},
end: {line: 8, column: 41}
}
]
]);
@@ -160,16 +160,16 @@ jobs:
{
prefix: "test.yaml (Line: 6, Col: 14)",
range: {
start: [7, 16],
end: [7, 40]
start: {line: 7, column: 16},
end: {line: 7, column: 40}
},
rawMessage: "Unrecognized function: 'fromJSON2'"
},
{
prefix: "test.yaml (Line: 6, Col: 14)",
range: {
start: [8, 24],
end: [8, 51]
start: {line: 8, column: 24},
end: {line: 8, column: 51}
},
rawMessage: "Unrecognized function: 'toJSON2'"
}
+4 -4
View File
@@ -32,8 +32,8 @@ describe("parseWorkflow", () => {
expect(result.context.errors.getErrors()).toEqual([
new TemplateValidationError("Required property is missing: runs-on", "test.yaml (Line: 4, Col: 5)", undefined, {
start: [4, 5],
end: [5, 24]
start: {line: 4, column: 5},
end: {line: 5, column: 24}
})
]);
});
@@ -62,8 +62,8 @@ jobs:
"test.yaml (Line: 6, Col: 13)",
undefined,
{
start: [6, 13],
end: [6, 37]
start: {line: 6, column: 13},
end: {line: 6, column: 37}
}
)
]);
@@ -455,7 +455,7 @@ class TemplateReader {
// Doesn't contain "${{"
// Check if value should still be evaluated as an expression
if (definitionInfo.definition instanceof StringDefinition && definitionInfo.definition.isExpression) {
const expression = this.parseIntoExpressionToken(token.range!, raw, allowedContext, token);
const expression = this.parseIntoExpressionToken(token.range!, raw, allowedContext, token, definitionInfo);
if (expression) {
return expression;
}
@@ -500,11 +500,11 @@ class TemplateReader {
);
let tr = token.range!;
if (tr.start[0] === tr.end[0]) {
if (tr.start.line === tr.end.line) {
// If it's a single line expression, adjust the range to only cover the sub-expression
tr = {
start: [tr.start[0], tr.start[1] + startExpression],
end: [tr.end[0], tr.start[1] + endExpression + 1]
start: {line: tr.start.line, column: tr.start.column + startExpression},
end: {line: tr.end.line, column: tr.start.column + endExpression + 1}
};
} else {
// Adjust the range to only cover the expression for multi-line strings
@@ -515,12 +515,12 @@ class TemplateReader {
const adjustedEnd = endExpression - beginningOfLine + 1;
tr = {
start: [tr.start[0] + adjustedStartLine, adjustedStart],
end: [tr.start[0] + adjustedStartLine, adjustedEnd]
start: {line: tr.start.line + adjustedStartLine, column: adjustedStart},
end: {line: tr.start.line + adjustedStartLine, column: adjustedEnd}
};
}
const expression = this.parseIntoExpressionToken(tr, rawExpression, allowedContext, token);
const expression = this.parseIntoExpressionToken(tr, rawExpression, allowedContext, token, definitionInfo);
if (!expression) {
// Record that we've hit an error but continue to validate any other expressions
@@ -615,9 +615,10 @@ class TemplateReader {
tr: TokenRange,
rawExpression: string,
allowedContext: string[],
token: TemplateToken
token: TemplateToken,
definitionInfo: DefinitionInfo | undefined
): ExpressionToken | undefined {
const parseExpressionResult = this.parseExpression(tr, rawExpression, allowedContext, token.definitionInfo);
const parseExpressionResult = this.parseExpression(tr, rawExpression, allowedContext, definitionInfo);
// Check for error
if (parseExpressionResult.error) {
@@ -42,11 +42,11 @@ export abstract class TemplateToken {
}
public get line(): number | undefined {
return this.range?.start[0];
return this.range?.start.line;
}
public get col(): number | undefined {
return this.range?.start[1];
return this.range?.start.column;
}
public get definition(): Definition | undefined {
@@ -1,4 +1,10 @@
export type Position = [line: number, character: number];
/** Represents the position within a template object */
export type Position = {
/** The one-based line value */
line: number;
/** The one-based column value */
column: number;
};
export type TokenRange = {
start: Position;
@@ -1,6 +1,6 @@
import {JSONObjectReader} from "../templates/json-object-reader";
import {TemplateSchema} from "../templates/schema";
import WorkflowSchema from "../workflow-v1.0.json";
import WorkflowSchema from "../workflow-v1.0.json" assert {type: "json"};
let schema: TemplateSchema;
@@ -74,8 +74,8 @@ it("YAML errors include range information", () => {
const error = context.errors.getErrors()[0];
expect(error.range).toEqual({
start: [7, 38],
end: [7, 63]
start: {line: 7, column: 38},
end: {line: 7, column: 63}
});
});
@@ -89,8 +89,8 @@ export class YamlObjectReader implements ObjectReader {
const elp = this.lineCounter.linePos(endPos);
return {
start: [slp.line, slp.col],
end: [elp.line, elp.col]
start: {line: slp.line, column: slp.col},
end: {line: elp.line, column: elp.col}
};
}
@@ -216,7 +216,7 @@ function rangeFromLinePos(linePos: [LinePos] | [LinePos, LinePos] | undefined):
return;
}
// TokenRange and linePos are both 1-based
const start: Position = [linePos[0].line, linePos[0].col];
const end: Position = linePos.length == 2 ? [linePos[1].line, linePos[1].col] : start;
const start: Position = {line: linePos[0].line, column: linePos[0].col};
const end: Position = linePos.length == 2 ? {line: linePos[1].line, column: linePos[1].col} : start;
return {start, end};
}
+2 -2
View File
@@ -1,12 +1,12 @@
{
"name": "browser-playground",
"version": "0.1.100",
"version": "0.1.109",
"description": "",
"private": true,
"main": "index.js",
"type": "module",
"dependencies": {
"@github/actions-languageserver": "^0.1.100",
"@github/actions-languageserver": "^0.1.109",
"monaco-editor-webpack-plugin": "^7.0.1",
"monaco-editor-workers": "^0.34.2",
"monaco-languageclient": "^4.0.3",
+1 -1
View File
@@ -1,5 +1,5 @@
{
"$schema": "node_modules/lerna/schemas/lerna-schema.json",
"useWorkspaces": true,
"version": "0.1.100"
"version": "0.1.109"
}
+119 -63
View File
@@ -18,28 +18,28 @@
},
"actions-expressions": {
"name": "@github/actions-expressions",
"version": "0.1.100",
"version": "0.1.109",
"license": "MIT",
"devDependencies": {
"@types/jest": "^29.0.3",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.7.4"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
}
},
"actions-languageserver": {
"name": "@github/actions-languageserver",
"version": "0.1.100",
"version": "0.1.109",
"license": "MIT",
"dependencies": {
"@github/actions-languageservice": "^0.1.100",
"@github/actions-workflow-parser": "^0.1.100",
"@octokit/rest": "^19.0.5",
"@github/actions-languageservice": "^0.1.109",
"@github/actions-workflow-parser": "^0.1.109",
"@octokit/rest": "^19.0.7",
"vscode-languageserver": "^8.0.2",
"vscode-languageserver-textdocument": "^1.0.7",
"yaml": "^2.1.3"
@@ -48,22 +48,22 @@
"@types/jest": "^29.0.3",
"fetch-mock": "^9.11.0",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
}
},
"actions-languageservice": {
"name": "@github/actions-languageservice",
"version": "0.1.100",
"version": "0.1.109",
"license": "MIT",
"dependencies": {
"@github/actions-expressions": "^0.1.100",
"@github/actions-workflow-parser": "^0.1.100",
"@github/actions-expressions": "^0.1.109",
"@github/actions-workflow-parser": "^0.1.109",
"vscode-languageserver-textdocument": "^1.0.7",
"vscode-languageserver-types": "^3.17.2",
"yaml": "^2.1.1"
@@ -71,21 +71,21 @@
"devDependencies": {
"@types/jest": "^29.0.3",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
}
},
"actions-workflow-parser": {
"name": "@github/actions-workflow-parser",
"version": "0.1.100",
"version": "0.1.109",
"license": "MIT",
"dependencies": {
"@github/actions-expressions": "^0.1.100",
"@github/actions-expressions": "^0.1.109",
"cronstrue": "^2.21.0",
"yaml": "^2.0.0-8"
},
@@ -95,20 +95,20 @@
"@typescript-eslint/parser": "^5.40.0",
"eslint": "7.32.0",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4"
},
"engines": {
"node": ">= 16"
"node": ">= 16.15"
}
},
"browser-playground": {
"version": "0.1.100",
"version": "0.1.109",
"license": "MIT",
"dependencies": {
"@github/actions-languageserver": "^0.1.100",
"@github/actions-languageserver": "^0.1.109",
"monaco-editor-webpack-plugin": "^7.0.1",
"monaco-editor-workers": "^0.34.2",
"monaco-languageclient": "^4.0.3",
@@ -2904,11 +2904,11 @@
"dev": true
},
"node_modules/@octokit/plugin-paginate-rest": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz",
"integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.0.0.tgz",
"integrity": "sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==",
"dependencies": {
"@octokit/types": "^8.0.0"
"@octokit/types": "^9.0.0"
},
"engines": {
"node": ">= 14"
@@ -2917,6 +2917,19 @@
"@octokit/core": ">=4"
}
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/openapi-types": {
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA=="
},
"node_modules/@octokit/plugin-paginate-rest/node_modules/@octokit/types": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"dependencies": {
"@octokit/openapi-types": "^16.0.0"
}
},
"node_modules/@octokit/plugin-request-log": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@octokit/plugin-request-log/-/plugin-request-log-1.0.4.tgz",
@@ -2926,11 +2939,11 @@
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
"integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.0.1.tgz",
"integrity": "sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==",
"dependencies": {
"@octokit/types": "^8.0.0",
"@octokit/types": "^9.0.0",
"deprecation": "^2.3.1"
},
"engines": {
@@ -2940,6 +2953,19 @@
"@octokit/core": ">=3"
}
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/openapi-types": {
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA=="
},
"node_modules/@octokit/plugin-rest-endpoint-methods/node_modules/@octokit/types": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"dependencies": {
"@octokit/openapi-types": "^16.0.0"
}
},
"node_modules/@octokit/request": {
"version": "6.2.2",
"resolved": "https://registry.npmjs.org/@octokit/request/-/request-6.2.2.tgz",
@@ -2970,14 +2996,14 @@
}
},
"node_modules/@octokit/rest": {
"version": "19.0.5",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz",
"integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==",
"version": "19.0.7",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.7.tgz",
"integrity": "sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==",
"dependencies": {
"@octokit/core": "^4.1.0",
"@octokit/plugin-paginate-rest": "^5.0.0",
"@octokit/plugin-paginate-rest": "^6.0.0",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-rest-endpoint-methods": "^6.7.0"
"@octokit/plugin-rest-endpoint-methods": "^7.0.0"
},
"engines": {
"node": ">= 14"
@@ -10998,9 +11024,9 @@
}
},
"node_modules/prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
"integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
"dev": true,
"bin": {
"prettier": "bin-prettier.js"
@@ -14535,7 +14561,7 @@
"requires": {
"@types/jest": "^29.0.3",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.7.4"
@@ -14544,13 +14570,13 @@
"@github/actions-languageserver": {
"version": "file:actions-languageserver",
"requires": {
"@github/actions-languageservice": "^0.1.100",
"@github/actions-workflow-parser": "^0.1.100",
"@octokit/rest": "^19.0.5",
"@github/actions-languageservice": "^0.1.109",
"@github/actions-workflow-parser": "^0.1.109",
"@octokit/rest": "^19.0.7",
"@types/jest": "^29.0.3",
"fetch-mock": "^9.11.0",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4",
@@ -14562,11 +14588,11 @@
"@github/actions-languageservice": {
"version": "file:actions-languageservice",
"requires": {
"@github/actions-expressions": "^0.1.100",
"@github/actions-workflow-parser": "^0.1.100",
"@github/actions-expressions": "^0.1.109",
"@github/actions-workflow-parser": "^0.1.109",
"@types/jest": "^29.0.3",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4",
@@ -14578,14 +14604,14 @@
"@github/actions-workflow-parser": {
"version": "file:actions-workflow-parser",
"requires": {
"@github/actions-expressions": "^0.1.100",
"@github/actions-expressions": "^0.1.109",
"@types/jest": "^29.0.3",
"@typescript-eslint/eslint-plugin": "^5.40.0",
"@typescript-eslint/parser": "^5.40.0",
"cronstrue": "^2.21.0",
"eslint": "7.32.0",
"jest": "^29.0.3",
"prettier": "^2.7.1",
"prettier": "^2.8.3",
"rimraf": "^3.0.2",
"ts-jest": "^29.0.3",
"typescript": "^4.8.4",
@@ -16280,11 +16306,26 @@
"dev": true
},
"@octokit/plugin-paginate-rest": {
"version": "5.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-5.0.1.tgz",
"integrity": "sha512-7A+rEkS70pH36Z6JivSlR7Zqepz3KVucEFVDnSrgHXzG7WLAzYwcHZbKdfTXHwuTHbkT1vKvz7dHl1+HNf6Qyw==",
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-paginate-rest/-/plugin-paginate-rest-6.0.0.tgz",
"integrity": "sha512-Sq5VU1PfT6/JyuXPyt04KZNVsFOSBaYOAq2QRZUwzVlI10KFvcbUo8lR258AAQL1Et60b0WuVik+zOWKLuDZxw==",
"requires": {
"@octokit/types": "^8.0.0"
"@octokit/types": "^9.0.0"
},
"dependencies": {
"@octokit/openapi-types": {
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA=="
},
"@octokit/types": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"requires": {
"@octokit/openapi-types": "^16.0.0"
}
}
}
},
"@octokit/plugin-request-log": {
@@ -16294,12 +16335,27 @@
"requires": {}
},
"@octokit/plugin-rest-endpoint-methods": {
"version": "6.7.0",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-6.7.0.tgz",
"integrity": "sha512-orxQ0fAHA7IpYhG2flD2AygztPlGYNAdlzYz8yrD8NDgelPfOYoRPROfEyIe035PlxvbYrgkfUZIhSBKju/Cvw==",
"version": "7.0.1",
"resolved": "https://registry.npmjs.org/@octokit/plugin-rest-endpoint-methods/-/plugin-rest-endpoint-methods-7.0.1.tgz",
"integrity": "sha512-pnCaLwZBudK5xCdrR823xHGNgqOzRnJ/mpC/76YPpNP7DybdsJtP7mdOwh+wYZxK5jqeQuhu59ogMI4NRlBUvA==",
"requires": {
"@octokit/types": "^8.0.0",
"@octokit/types": "^9.0.0",
"deprecation": "^2.3.1"
},
"dependencies": {
"@octokit/openapi-types": {
"version": "16.0.0",
"resolved": "https://registry.npmjs.org/@octokit/openapi-types/-/openapi-types-16.0.0.tgz",
"integrity": "sha512-JbFWOqTJVLHZSUUoF4FzAZKYtqdxWu9Z5m2QQnOyEa04fOFljvyh7D3GYKbfuaSWisqehImiVIMG4eyJeP5VEA=="
},
"@octokit/types": {
"version": "9.0.0",
"resolved": "https://registry.npmjs.org/@octokit/types/-/types-9.0.0.tgz",
"integrity": "sha512-LUewfj94xCMH2rbD5YJ+6AQ4AVjFYTgpp6rboWM5T7N3IsIF65SBEOVcYMGAEzO/kKNiNaW4LoWtoThOhH06gw==",
"requires": {
"@octokit/openapi-types": "^16.0.0"
}
}
}
},
"@octokit/request": {
@@ -16326,14 +16382,14 @@
}
},
"@octokit/rest": {
"version": "19.0.5",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.5.tgz",
"integrity": "sha512-+4qdrUFq2lk7Va+Qff3ofREQWGBeoTKNqlJO+FGjFP35ZahP+nBenhZiGdu8USSgmq4Ky3IJ/i4u0xbLqHaeow==",
"version": "19.0.7",
"resolved": "https://registry.npmjs.org/@octokit/rest/-/rest-19.0.7.tgz",
"integrity": "sha512-HRtSfjrWmWVNp2uAkEpQnuGMJsu/+dBr47dRc5QVgsCbnIc1+GFEaoKBWkYG+zjrsHpSqcAElMio+n10c0b5JA==",
"requires": {
"@octokit/core": "^4.1.0",
"@octokit/plugin-paginate-rest": "^5.0.0",
"@octokit/plugin-paginate-rest": "^6.0.0",
"@octokit/plugin-request-log": "^1.0.4",
"@octokit/plugin-rest-endpoint-methods": "^6.7.0"
"@octokit/plugin-rest-endpoint-methods": "^7.0.0"
}
},
"@octokit/types": {
@@ -17506,7 +17562,7 @@
"browser-playground": {
"version": "file:browser-playground",
"requires": {
"@github/actions-languageserver": "^0.1.100",
"@github/actions-languageserver": "^0.1.109",
"css-loader": "^6.7.2",
"monaco-editor-webpack-plugin": "^7.0.1",
"monaco-editor-workers": "^0.34.2",
@@ -22508,9 +22564,9 @@
"dev": true
},
"prettier": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.7.1.tgz",
"integrity": "sha512-ujppO+MkdPqoVINuDFDRLClm7D78qbDt0/NR+wp5FqEZOoTNAjPHWj17QRhu7geIHJfcNhRk1XVQmF8Bp3ye+g==",
"version": "2.8.3",
"resolved": "https://registry.npmjs.org/prettier/-/prettier-2.8.3.tgz",
"integrity": "sha512-tJ/oJ4amDihPoufT5sM0Z1SKEuKay8LfVAMlbbhnnkvt6BUserZylqo2PN+p9KeljLr0OHa2rXHU1T8reeoTrw==",
"dev": true
},
"pretty-format": {