Use tokenPath for value providers
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import {complete} from "./complete";
|
||||
import {WorkflowContext} from "./context/workflow-context";
|
||||
import {getPositionFromCursor} from "./test-utils/cursor-position";
|
||||
import {Value, ValueProviderConfig, WorkflowContext} from "./value-providers/config";
|
||||
import {Value, ValueProviderConfig} from "./value-providers/config";
|
||||
|
||||
describe("completion", () => {
|
||||
it("runs-on", async () => {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import {complete as completeExpression} from "@github/actions-expressions";
|
||||
import {convertWorkflowTemplate, isMapping, isSequence, isString, parseWorkflow} from "@github/actions-workflow-parser";
|
||||
import {convertWorkflowTemplate, isSequence, isString, parseWorkflow} from "@github/actions-workflow-parser";
|
||||
import {CLOSE_EXPRESSION, OPEN_EXPRESSION} from "@github/actions-workflow-parser/templates/template-constants";
|
||||
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/index";
|
||||
import {MappingToken} from "@github/actions-workflow-parser/templates/tokens/mapping-token";
|
||||
@@ -9,10 +9,11 @@ import {Position, TextDocument} from "vscode-languageserver-textdocument";
|
||||
import {CompletionItem} from "vscode-languageserver-types";
|
||||
import {ContextProviderConfig} from "./context-providers/config";
|
||||
import {getContext} from "./context-providers/default";
|
||||
import {getWorkflowContext, WorkflowContext} from "./context/workflow-context";
|
||||
import {nullTrace} from "./nulltrace";
|
||||
import {findToken} from "./utils/find-token";
|
||||
import {transform} from "./utils/transform";
|
||||
import {Value, ValueProviderConfig, WorkflowContext} from "./value-providers/config";
|
||||
import {Value, ValueProviderConfig} from "./value-providers/config";
|
||||
import {defaultValueProviders} from "./value-providers/default";
|
||||
import {definitionValues} from "./value-providers/definition";
|
||||
|
||||
@@ -60,7 +61,7 @@ export async function complete(
|
||||
return [];
|
||||
}
|
||||
|
||||
const {token, keyToken, parent, parentKey} = findToken(newPos, result.value);
|
||||
const {token, keyToken, parent, path} = findToken(newPos, result.value);
|
||||
const template = convertWorkflowTemplate(result.context, result.value);
|
||||
|
||||
// If we are inside an expression, take a different code-path. The workflow parser does not correctly create
|
||||
@@ -84,15 +85,14 @@ export async function complete(
|
||||
}
|
||||
}
|
||||
|
||||
const workflowContext = {uri: textDocument.uri, template: template};
|
||||
const values = await getValues(token, parent, parentKey, valueProviderConfig, workflowContext);
|
||||
const workflowContext = getWorkflowContext(textDocument.uri, template, path);
|
||||
const values = await getValues(token, parent, valueProviderConfig, workflowContext);
|
||||
return values.map(value => CompletionItem.create(value.label));
|
||||
}
|
||||
|
||||
async function getValues(
|
||||
token: TemplateToken | null,
|
||||
parent: TemplateToken | null,
|
||||
parentKey: TemplateToken | null,
|
||||
valueProviderConfig: ValueProviderConfig | undefined,
|
||||
workflowContext: WorkflowContext
|
||||
): Promise<Value[]> {
|
||||
@@ -100,7 +100,7 @@ async function getValues(
|
||||
return [];
|
||||
}
|
||||
|
||||
const existingValues = getExistingValues(token, parent, parentKey);
|
||||
const existingValues = getExistingValues(token, parent);
|
||||
|
||||
if (token?.definition?.key) {
|
||||
const customValues = await valueProviderConfig?.getCustomValues(token.definition.key, workflowContext);
|
||||
@@ -130,18 +130,16 @@ async function getValues(
|
||||
return filterAndSortCompletionOptions(values, existingValues);
|
||||
}
|
||||
|
||||
function getExistingValues(token: TemplateToken | null, parent: TemplateToken, parentKey: TemplateToken | null) {
|
||||
function getExistingValues(token: TemplateToken | null, parent: TemplateToken) {
|
||||
// For incomplete YAML, we may only have a parent token
|
||||
if (token) {
|
||||
if (!isString(token)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (isMapping(parent) && parentKey && isString(parentKey)) {
|
||||
return new Set<string>([parentKey.value]);
|
||||
}
|
||||
if (isSequence(parent)) {
|
||||
const sequenceValues = new Set<string>();
|
||||
|
||||
for (let i = 0; i < parent.count; i++) {
|
||||
const t = parent.get(i);
|
||||
if (isString(t)) {
|
||||
@@ -149,6 +147,7 @@ function getExistingValues(token: TemplateToken | null, parent: TemplateToken, p
|
||||
sequenceValues.add(t.value);
|
||||
}
|
||||
}
|
||||
|
||||
return sequenceValues;
|
||||
}
|
||||
}
|
||||
@@ -157,9 +156,11 @@ function getExistingValues(token: TemplateToken | null, parent: TemplateToken, p
|
||||
// No token and parent is a mapping, so we're completing a key
|
||||
const mapKeys = new Set<string>();
|
||||
const mapToken = parent as MappingToken;
|
||||
|
||||
for (let i = 0; i < mapToken.count; i++) {
|
||||
const key = mapToken.get(i).key;
|
||||
if (key.isLiteral && isString(key)) {
|
||||
|
||||
if (isString(key)) {
|
||||
mapKeys.add(key.value);
|
||||
}
|
||||
}
|
||||
@@ -169,7 +170,7 @@ function getExistingValues(token: TemplateToken | null, parent: TemplateToken, p
|
||||
}
|
||||
|
||||
function filterAndSortCompletionOptions(options: Value[], existingValues?: Set<string>) {
|
||||
options = options.filter(x => !existingValues || !existingValues.has(x.label));
|
||||
options = options.filter(x => !existingValues?.has(x.label));
|
||||
options.sort((a, b) => a.label.localeCompare(b.label));
|
||||
return options;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
import {convertWorkflowTemplate, parseWorkflow, WorkflowTemplate} from "@github/actions-workflow-parser";
|
||||
import {nullTrace} from "../nulltrace";
|
||||
import {getPositionFromCursor} from "../test-utils/cursor-position";
|
||||
import {findToken} from "../utils/find-token";
|
||||
import {getWorkflowContext, WorkflowContext} from "./workflow-context";
|
||||
|
||||
function testGetWorkflowContext(input: string): [context: WorkflowContext, template?: WorkflowTemplate] {
|
||||
const [textDocument, pos] = getPositionFromCursor(input);
|
||||
const result = parseWorkflow(
|
||||
"wf.yaml",
|
||||
[
|
||||
{
|
||||
content: textDocument.getText(),
|
||||
name: "wf.yaml"
|
||||
}
|
||||
],
|
||||
nullTrace
|
||||
);
|
||||
|
||||
let template: WorkflowTemplate | undefined;
|
||||
|
||||
if (result.value) {
|
||||
template = convertWorkflowTemplate(result.context, result.value);
|
||||
}
|
||||
|
||||
const {path} = findToken(pos, result.value);
|
||||
|
||||
return [getWorkflowContext(textDocument.uri, template, path), template];
|
||||
}
|
||||
|
||||
describe("getWorkflowContext", () => {
|
||||
it("context for workflow", () => {
|
||||
const [context, template] = testGetWorkflowContext(`on: push
|
||||
name: te|st
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- echo Hello`);
|
||||
expect(context.uri).not.toBe("");
|
||||
expect(context.template).not.toBeUndefined();
|
||||
expect(context.job).toBeUndefined();
|
||||
expect(context.step).toBeUndefined();
|
||||
});
|
||||
|
||||
it("context for workflow job", () => {
|
||||
const [context, template] = testGetWorkflowContext(`on: push
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-lat|est
|
||||
steps:
|
||||
- run: echo Hello`);
|
||||
expect(context.uri).not.toBe("");
|
||||
expect(context.template).not.toBeUndefined();
|
||||
expect(context.job).not.toBeUndefined();
|
||||
expect(context.step).toBeUndefined();
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,40 @@
|
||||
import {WorkflowTemplate} from "@github/actions-workflow-parser";
|
||||
import {JobConfig, StepConfig} from "@github/actions-workflow-parser/model/workflow-template";
|
||||
import {StringToken} from "@github/actions-workflow-parser/templates/tokens/string-token";
|
||||
import {TemplateToken} from "@github/actions-workflow-parser/templates/tokens/template-token";
|
||||
|
||||
export interface WorkflowContext {
|
||||
uri: string;
|
||||
|
||||
template: WorkflowTemplate | undefined;
|
||||
|
||||
/** If the context is for a position within a job, this will be the job */
|
||||
job?: JobConfig;
|
||||
|
||||
/** If the context is for a position within a step, this will the step */
|
||||
step?: StepConfig;
|
||||
}
|
||||
|
||||
export function getWorkflowContext(
|
||||
uri: string,
|
||||
template: WorkflowTemplate | undefined,
|
||||
tokenPath: TemplateToken[]
|
||||
): WorkflowContext {
|
||||
const context: WorkflowContext = {uri: uri, template};
|
||||
|
||||
if (template) {
|
||||
// Iterate through the token path to find the job and step
|
||||
for (let i = 0; i < tokenPath.length; ++i) {
|
||||
const token = tokenPath[i];
|
||||
|
||||
switch (token.definition?.key) {
|
||||
case "job-id": {
|
||||
const jobID = (token as StringToken).value;
|
||||
context.job = template.jobs.find(job => job.id === jobID);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return context;
|
||||
}
|
||||
@@ -23,7 +23,7 @@ function testFindToken(input: string): {
|
||||
parent: testTokenInfo | null;
|
||||
key: testTokenInfo | null;
|
||||
token: testTokenInfo | null;
|
||||
parentKey: testTokenInfo | null;
|
||||
path: testTokenInfo[];
|
||||
} {
|
||||
const [textDocument, pos] = getPositionFromCursor(input);
|
||||
const result = parseWorkflow(
|
||||
@@ -41,17 +41,17 @@ function testFindToken(input: string): {
|
||||
|
||||
return {
|
||||
parent: getTokenInfo(r.parent),
|
||||
parentKey: getTokenInfo(r.parentKey),
|
||||
key: getTokenInfo(r.keyToken),
|
||||
token: getTokenInfo(r.token)
|
||||
token: getTokenInfo(r.token),
|
||||
path: r.path.map(x => getTokenInfo(x)!)
|
||||
};
|
||||
}
|
||||
|
||||
describe("find-token", () => {
|
||||
it("on string key", () => {
|
||||
expect(testFindToken(`o|n: push`)).toEqual({
|
||||
path: [["workflow-root-strict", TokenType.Mapping]],
|
||||
parent: ["workflow-root-strict", TokenType.Mapping],
|
||||
parentKey: null,
|
||||
key: null,
|
||||
token: [null, TokenType.String, "on"]
|
||||
});
|
||||
@@ -59,8 +59,11 @@ describe("find-token", () => {
|
||||
|
||||
it("on string value", () => {
|
||||
expect(testFindToken(`on: pu|sh`)).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "on"]
|
||||
],
|
||||
parent: ["workflow-root-strict", TokenType.Mapping],
|
||||
parentKey: null,
|
||||
key: [null, TokenType.String, "on"],
|
||||
token: ["on-strict", TokenType.String, "push"]
|
||||
});
|
||||
@@ -71,8 +74,12 @@ describe("find-token", () => {
|
||||
testFindToken(`on:
|
||||
pu|sh:`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "on"],
|
||||
["on-mapping-strict", TokenType.Mapping]
|
||||
],
|
||||
parent: ["on-mapping-strict", TokenType.Mapping],
|
||||
parentKey: [null, TokenType.String, "on"],
|
||||
key: null,
|
||||
token: [null, TokenType.String, "push"]
|
||||
});
|
||||
@@ -83,8 +90,12 @@ describe("find-token", () => {
|
||||
testFindToken(`on:
|
||||
- pu|sh`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "on"],
|
||||
["on-strict", TokenType.Sequence]
|
||||
],
|
||||
parent: ["on-strict", TokenType.Sequence],
|
||||
parentKey: null,
|
||||
key: null,
|
||||
token: ["non-empty-string", TokenType.String, "push"]
|
||||
});
|
||||
@@ -95,8 +106,12 @@ describe("find-token", () => {
|
||||
testFindToken(`on:
|
||||
-| push`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "on"],
|
||||
["on-strict", TokenType.Sequence]
|
||||
],
|
||||
parent: ["on-strict", TokenType.Sequence],
|
||||
parentKey: null,
|
||||
key: null,
|
||||
token: null
|
||||
});
|
||||
@@ -108,8 +123,12 @@ describe("find-token", () => {
|
||||
- push
|
||||
- pull_request|`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "on"],
|
||||
["on-strict", TokenType.Sequence]
|
||||
],
|
||||
parent: ["on-strict", TokenType.Sequence],
|
||||
parentKey: null,
|
||||
key: null,
|
||||
token: ["non-empty-string", TokenType.String, "pull_request"]
|
||||
});
|
||||
@@ -122,8 +141,16 @@ jobs:
|
||||
build:
|
||||
runs-on: [ubuntu-latest, self|`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping],
|
||||
[null, TokenType.String, "runs-on"],
|
||||
["runs-on", TokenType.Sequence]
|
||||
],
|
||||
parent: ["runs-on", TokenType.Sequence],
|
||||
parentKey: null,
|
||||
key: null,
|
||||
token: ["non-empty-string", TokenType.String, "self"]
|
||||
});
|
||||
@@ -135,8 +162,8 @@ jobs:
|
||||
jo|bs:
|
||||
build:`)
|
||||
).toEqual({
|
||||
path: [["workflow-root-strict", TokenType.Mapping]],
|
||||
parent: ["workflow-root-strict", TokenType.Mapping],
|
||||
parentKey: null,
|
||||
key: null,
|
||||
token: [null, TokenType.String, "jobs"]
|
||||
});
|
||||
@@ -149,8 +176,15 @@ jobs:
|
||||
build:
|
||||
runs-on: ubu|`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping],
|
||||
[null, TokenType.String, "runs-on"]
|
||||
],
|
||||
parent: ["job-factory", TokenType.Mapping],
|
||||
parentKey: ["job-id", TokenType.String, "build"],
|
||||
key: [null, TokenType.String, "runs-on"],
|
||||
token: ["runs-on", TokenType.String, "ubu"]
|
||||
});
|
||||
@@ -163,8 +197,14 @@ jobs:
|
||||
build:
|
||||
run|s-on: ubu`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping]
|
||||
],
|
||||
parent: ["job-factory", TokenType.Mapping],
|
||||
parentKey: ["job-id", TokenType.String, "build"],
|
||||
key: null,
|
||||
token: [null, TokenType.String, "runs-on"]
|
||||
});
|
||||
@@ -177,8 +217,14 @@ jobs:
|
||||
build:
|
||||
continue-on-error:|`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping]
|
||||
],
|
||||
parent: ["job-factory", TokenType.Mapping],
|
||||
parentKey: ["job-id", TokenType.String, "build"],
|
||||
key: [null, TokenType.String, "continue-on-error"],
|
||||
token: ["boolean-strategy-context", TokenType.Null, ""]
|
||||
});
|
||||
@@ -191,8 +237,14 @@ jobs:
|
||||
build:
|
||||
container:|`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping]
|
||||
],
|
||||
parent: ["job-factory", TokenType.Mapping],
|
||||
parentKey: ["job-id", TokenType.String, "build"],
|
||||
key: [null, TokenType.String, "container"],
|
||||
token: ["container", TokenType.String, ""]
|
||||
});
|
||||
@@ -205,8 +257,13 @@ jobs:
|
||||
build:
|
||||
continue-on-error:|foo`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"]
|
||||
],
|
||||
parent: ["jobs", TokenType.Mapping],
|
||||
parentKey: [null, TokenType.String, "jobs"],
|
||||
key: ["job-id", TokenType.String, "build"],
|
||||
token: ["job", TokenType.String, "continue-on-error:foo"]
|
||||
});
|
||||
@@ -219,8 +276,14 @@ jobs:
|
||||
build:
|
||||
continue-on-error:| foo`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping]
|
||||
],
|
||||
parent: ["job-factory", TokenType.Mapping],
|
||||
parentKey: null,
|
||||
key: null,
|
||||
token: null
|
||||
});
|
||||
@@ -233,8 +296,14 @@ jobs:
|
||||
build:
|
||||
continue-on-error|: foo`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping]
|
||||
],
|
||||
parent: ["job-factory", TokenType.Mapping],
|
||||
parentKey: ["job-id", TokenType.String, "build"],
|
||||
key: null,
|
||||
token: [null, TokenType.String, "continue-on-error"]
|
||||
});
|
||||
@@ -247,8 +316,13 @@ jobs:
|
||||
build:
|
||||
runs-|`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"]
|
||||
],
|
||||
parent: ["jobs", TokenType.Mapping],
|
||||
parentKey: [null, TokenType.String, "jobs"],
|
||||
key: ["job-id", TokenType.String, "build"],
|
||||
token: ["job", TokenType.String, "runs-"]
|
||||
});
|
||||
@@ -262,8 +336,13 @@ jobs:
|
||||
runs-|
|
||||
#`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"]
|
||||
],
|
||||
parent: ["jobs", TokenType.Mapping],
|
||||
parentKey: [null, TokenType.String, "jobs"],
|
||||
key: ["job-id", TokenType.String, "build"],
|
||||
token: ["job", TokenType.String, "runs-"]
|
||||
});
|
||||
@@ -277,8 +356,15 @@ jobs:
|
||||
concurrency:
|
||||
runs-on: ubu|`)
|
||||
).toEqual({
|
||||
path: [
|
||||
["workflow-root-strict", TokenType.Mapping],
|
||||
[null, TokenType.String, "jobs"],
|
||||
["jobs", TokenType.Mapping],
|
||||
["job-id", TokenType.String, "build"],
|
||||
["job-factory", TokenType.Mapping],
|
||||
[null, TokenType.String, "runs-on"]
|
||||
],
|
||||
parent: ["job-factory", TokenType.Mapping],
|
||||
parentKey: ["job-id", TokenType.String, "build"],
|
||||
key: [null, TokenType.String, "runs-on"],
|
||||
token: ["runs-on", TokenType.String, "ubu"]
|
||||
});
|
||||
|
||||
@@ -11,10 +11,11 @@ export function findInnerToken(pos: Position, root?: TemplateToken) {
|
||||
}
|
||||
|
||||
export type TokenResult = {
|
||||
token: TemplateToken | null;
|
||||
keyToken: TemplateToken | null;
|
||||
parent: TemplateToken | null;
|
||||
parentKey: TemplateToken | null;
|
||||
keyToken: TemplateToken | null;
|
||||
token: TemplateToken | null;
|
||||
|
||||
path: TemplateToken[];
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -35,23 +36,24 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult {
|
||||
token: null,
|
||||
keyToken: null,
|
||||
parent: null,
|
||||
parentKey: null
|
||||
path: []
|
||||
};
|
||||
}
|
||||
|
||||
let lastMatchingToken: TemplateToken | null = null;
|
||||
let lastMatching: TokenResult | null = null;
|
||||
|
||||
const s: TokenResult[] = [
|
||||
{
|
||||
token: root,
|
||||
keyToken: null,
|
||||
parent: null,
|
||||
parentKey: null
|
||||
path: []
|
||||
}
|
||||
];
|
||||
|
||||
while (s.length > 0) {
|
||||
const {parent, token, keyToken, parentKey} = s.shift()!;
|
||||
const result = s.shift()!;
|
||||
const {parent, token, keyToken, path} = result;
|
||||
if (!token) {
|
||||
break;
|
||||
}
|
||||
@@ -61,7 +63,7 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult {
|
||||
}
|
||||
|
||||
// Pos is in token, remember this token
|
||||
lastMatchingToken = token;
|
||||
lastMatching = result;
|
||||
|
||||
// Position is in token, enqueue children if there are any
|
||||
switch (token.templateTokenType) {
|
||||
@@ -76,7 +78,7 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult {
|
||||
parent: mappingToken,
|
||||
keyToken: null,
|
||||
token: key,
|
||||
parentKey: keyToken
|
||||
path: [...path, mappingToken]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -87,7 +89,7 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult {
|
||||
parent: mappingToken,
|
||||
keyToken: key,
|
||||
token: value,
|
||||
parentKey: keyToken
|
||||
path: [...path, mappingToken]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -95,7 +97,7 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult {
|
||||
parent: mappingToken,
|
||||
keyToken: key,
|
||||
token: value,
|
||||
parentKey: keyToken
|
||||
path: [...path, mappingToken, key]
|
||||
});
|
||||
}
|
||||
continue;
|
||||
@@ -107,7 +109,7 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult {
|
||||
parent: sequenceToken,
|
||||
keyToken: null,
|
||||
token: sequenceToken.get(i),
|
||||
parentKey: null
|
||||
path: [...path, sequenceToken]
|
||||
});
|
||||
}
|
||||
continue;
|
||||
@@ -117,16 +119,16 @@ export function findToken(pos: Position, root?: TemplateToken): TokenResult {
|
||||
token,
|
||||
keyToken,
|
||||
parent,
|
||||
parentKey
|
||||
path
|
||||
};
|
||||
}
|
||||
|
||||
// Did not find a matching token, return the last matching token as parent
|
||||
return {
|
||||
token: null,
|
||||
parent: lastMatchingToken,
|
||||
parent: lastMatching?.token ?? null,
|
||||
keyToken: null,
|
||||
parentKey: null
|
||||
path: lastMatching?.token ? [...(lastMatching?.path || []), lastMatching?.token] : []
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import {WorkflowTemplate} from "@github/actions-workflow-parser/.";
|
||||
import {WorkflowContext} from "../context/workflow-context";
|
||||
|
||||
export interface Value {
|
||||
label: string;
|
||||
@@ -7,10 +7,6 @@ export interface Value {
|
||||
|
||||
export type ValueProvider = () => Value[];
|
||||
|
||||
export interface WorkflowContext {
|
||||
uri: string;
|
||||
template: WorkflowTemplate | undefined;
|
||||
}
|
||||
export interface ValueProviderConfig {
|
||||
getCustomValues: (key: string, context: WorkflowContext) => Promise<Value[] | undefined>;
|
||||
getActionInputs?: (owner: string, name: string, ref: string, path?: string) => Promise<ActionInput[]>;
|
||||
|
||||
@@ -1,8 +1,9 @@
|
||||
import {Value, WorkflowContext} from "./config";
|
||||
import {getJobNames} from "./needs";
|
||||
import {WorkflowContext} from "../context/workflow-context";
|
||||
import {Value} from "./config";
|
||||
import {needs} from "./needs";
|
||||
|
||||
export const defaultValueProviders: {[key: string]: (workflowContext: WorkflowContext) => Value[]} = {
|
||||
needs: (workflowContext: WorkflowContext) => getJobNames(workflowContext.template),
|
||||
needs,
|
||||
"runs-on": () =>
|
||||
stringsToValues([
|
||||
"ubuntu-latest",
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import {WorkflowTemplate} from "@github/actions-workflow-parser/model/workflow-template";
|
||||
import {WorkflowContext} from "../context/workflow-context";
|
||||
import {Value} from "./config";
|
||||
|
||||
export function getJobNames(template: WorkflowTemplate | undefined): Value[] {
|
||||
if (!template) {
|
||||
export function needs(context: WorkflowContext): Value[] {
|
||||
if (!context.template) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const uniquejobIDs = new Set(template.jobs.map(j => j.id)).values();
|
||||
return Array.from(uniquejobIDs).map(x => ({label: x}));
|
||||
const uniquejobIDs = new Set(context.template.jobs.map(j => j.id)).values();
|
||||
return Array.from(uniquejobIDs)
|
||||
.filter(x => x !== context.job?.id)
|
||||
.map(x => ({label: x}));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user