Merge pull request #320 from actions/allanguigou/default-case

Remove experimental flag for `case` function
This commit is contained in:
Allan Guigou
2026-01-29 13:10:33 -05:00
committed by GitHub
5 changed files with 15 additions and 56 deletions
+3 -7
View File
@@ -35,6 +35,7 @@ export function complete(
context: Dictionary, context: Dictionary,
extensionFunctions: FunctionInfo[], extensionFunctions: FunctionInfo[],
functions?: Map<string, FunctionDefinition>, functions?: Map<string, FunctionDefinition>,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
featureFlags?: FeatureFlags featureFlags?: FeatureFlags
): CompletionItem[] { ): CompletionItem[] {
// Lex // Lex
@@ -66,7 +67,7 @@ export function complete(
const result = contextKeys(context); const result = contextKeys(context);
// Merge with functions // Merge with functions
result.push(...functionItems(extensionFunctions, featureFlags)); result.push(...functionItems(extensionFunctions));
return result; return result;
} }
@@ -91,15 +92,10 @@ export function complete(
return contextKeys(result); return contextKeys(result);
} }
function functionItems(extensionFunctions: FunctionInfo[], featureFlags?: FeatureFlags): CompletionItem[] { function functionItems(extensionFunctions: FunctionInfo[]): CompletionItem[] {
const result: CompletionItem[] = []; const result: CompletionItem[] = [];
const flags = featureFlags ?? new FeatureFlags();
for (const fdef of [...Object.values(wellKnownFunctions), ...extensionFunctions]) { for (const fdef of [...Object.values(wellKnownFunctions), ...extensionFunctions]) {
// Filter out case function if feature is disabled
if (fdef.name === "case" && !flags.isEnabled("allowCaseFunction")) {
continue;
}
result.push({ result.push({
label: fdef.name, label: fdef.name,
description: fdef.description, description: fdef.description,
+1 -5
View File
@@ -51,11 +51,7 @@ describe("FeatureFlags", () => {
it("returns all features when all is enabled", () => { it("returns all features when all is enabled", () => {
const flags = new FeatureFlags({all: true}); const flags = new FeatureFlags({all: true});
expect(flags.getEnabledFeatures()).toEqual([ expect(flags.getEnabledFeatures()).toEqual(["missingInputsQuickfix", "blockScalarChompingWarning"]);
"missingInputsQuickfix",
"blockScalarChompingWarning",
"allowCaseFunction"
]);
}); });
}); });
}); });
+1 -11
View File
@@ -28,12 +28,6 @@ export interface ExperimentalFeatures {
* @default false * @default false
*/ */
blockScalarChompingWarning?: boolean; blockScalarChompingWarning?: boolean;
/**
* Enable the case() function in expressions.
* @default false
*/
allowCaseFunction?: boolean;
} }
/** /**
@@ -45,11 +39,7 @@ export type ExperimentalFeatureKey = Exclude<keyof ExperimentalFeatures, "all">;
* All known experimental feature keys. * All known experimental feature keys.
* This list must be kept in sync with the ExperimentalFeatures interface. * This list must be kept in sync with the ExperimentalFeatures interface.
*/ */
const allFeatureKeys: ExperimentalFeatureKey[] = [ const allFeatureKeys: ExperimentalFeatureKey[] = ["missingInputsQuickfix", "blockScalarChompingWarning"];
"missingInputsQuickfix",
"blockScalarChompingWarning",
"allowCaseFunction"
];
export class FeatureFlags { export class FeatureFlags {
private readonly features: ExperimentalFeatures; private readonly features: ExperimentalFeatures;
@@ -1,5 +1,5 @@
/* eslint-disable @typescript-eslint/no-non-null-assertion */ /* eslint-disable @typescript-eslint/no-non-null-assertion */
import {data, DescriptionDictionary, FeatureFlags} from "@actions/expressions"; import {data, DescriptionDictionary} from "@actions/expressions";
import {CompletionItem, CompletionItemKind, MarkupContent} from "vscode-languageserver-types"; import {CompletionItem, CompletionItemKind, MarkupContent} from "vscode-languageserver-types";
import {complete, getExpressionInput} from "./complete.js"; import {complete, getExpressionInput} from "./complete.js";
import {ContextProviderConfig} from "./context-providers/config.js"; import {ContextProviderConfig} from "./context-providers/config.js";
@@ -69,8 +69,7 @@ describe("expressions", () => {
it("single region", async () => { it("single region", async () => {
const input = "run-name: ${{ | }}"; const input = "run-name: ${{ | }}";
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input), {
contextProviderConfig, contextProviderConfig
featureFlags: new FeatureFlags({allowCaseFunction: true})
}); });
expect(result.map(x => x.label)).toEqual([ expect(result.map(x => x.label)).toEqual([
@@ -113,8 +112,7 @@ describe("expressions", () => {
it("single region with existing input", async () => { it("single region with existing input", async () => {
const input = "run-name: ${{ g| }}"; const input = "run-name: ${{ g| }}";
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input), {
contextProviderConfig, contextProviderConfig
featureFlags: new FeatureFlags({allowCaseFunction: true})
}); });
expect(result.map(x => x.label)).toEqual([ expect(result.map(x => x.label)).toEqual([
@@ -135,8 +133,7 @@ describe("expressions", () => {
it("single region with existing condition", async () => { it("single region with existing condition", async () => {
const input = "run-name: ${{ g| == 'test' }}"; const input = "run-name: ${{ g| == 'test' }}";
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input), {
contextProviderConfig, contextProviderConfig
featureFlags: new FeatureFlags({allowCaseFunction: true})
}); });
expect(result.map(x => x.label)).toEqual([ expect(result.map(x => x.label)).toEqual([
@@ -157,8 +154,7 @@ describe("expressions", () => {
it("multiple regions with partial function", async () => { it("multiple regions with partial function", async () => {
const input = "run-name: Run a ${{ inputs.test }} one-line script ${{ from|('test') == inputs.name }}"; const input = "run-name: Run a ${{ inputs.test }} one-line script ${{ from|('test') == inputs.name }}";
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input), {
contextProviderConfig, contextProviderConfig
featureFlags: new FeatureFlags({allowCaseFunction: true})
}); });
expect(result.map(x => x.label)).toEqual([ expect(result.map(x => x.label)).toEqual([
@@ -179,8 +175,7 @@ describe("expressions", () => {
it("multiple regions - first region", async () => { it("multiple regions - first region", async () => {
const input = "run-name: test-${{ git| == 1 }}-${{ github.event }}"; const input = "run-name: test-${{ git| == 1 }}-${{ github.event }}";
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input), {
contextProviderConfig, contextProviderConfig
featureFlags: new FeatureFlags({allowCaseFunction: true})
}); });
expect(result.map(x => x.label)).toEqual([ expect(result.map(x => x.label)).toEqual([
@@ -201,8 +196,7 @@ describe("expressions", () => {
it("multiple regions", async () => { it("multiple regions", async () => {
const input = "run-name: test-${{ github }}-${{ | }}"; const input = "run-name: test-${{ github }}-${{ | }}";
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input), {
contextProviderConfig, contextProviderConfig
featureFlags: new FeatureFlags({allowCaseFunction: true})
}); });
expect(result.map(x => x.label)).toEqual([ expect(result.map(x => x.label)).toEqual([
@@ -1181,8 +1175,7 @@ jobs:
`; `;
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input), {
contextProviderConfig, contextProviderConfig
featureFlags: new FeatureFlags({allowCaseFunction: true})
}); });
expect(result.map(x => x.label)).toEqual([ expect(result.map(x => x.label)).toEqual([
"env", "env",
+2 -18
View File
@@ -6,7 +6,6 @@ import {getPositionFromCursor} from "./test-utils/cursor-position.js";
import {TestLogger} from "./test-utils/logger.js"; import {TestLogger} from "./test-utils/logger.js";
import {clearCache} from "./utils/workflow-cache.js"; import {clearCache} from "./utils/workflow-cache.js";
import {ValueProviderConfig, ValueProviderKind} from "./value-providers/config.js"; import {ValueProviderConfig, ValueProviderKind} from "./value-providers/config.js";
import {FeatureFlags} from "@actions/expressions/features";
registerLogger(new TestLogger()); registerLogger(new TestLogger());
@@ -898,11 +897,9 @@ jobs:
}); });
describe("expression completions", () => { describe("expression completions", () => {
it("include case function when enabled", async () => { it("includes case function", async () => {
const input = "on: push\njobs:\n build:\n runs-on: ${{ c|"; const input = "on: push\njobs:\n build:\n runs-on: ${{ c|";
const result = await complete(...getPositionFromCursor(input), { const result = await complete(...getPositionFromCursor(input));
featureFlags: new FeatureFlags({allowCaseFunction: true})
});
expect(result).not.toBeUndefined(); expect(result).not.toBeUndefined();
// Expression completions starting with 'c': case, contains // Expression completions starting with 'c': case, contains
@@ -910,18 +907,5 @@ jobs:
expect(labels).toContain("case"); expect(labels).toContain("case");
expect(labels).toContain("contains"); expect(labels).toContain("contains");
}); });
it("exclude case function when disabled", async () => {
const input = "on: push\njobs:\n build:\n runs-on: ${{ c|";
const result = await complete(...getPositionFromCursor(input), {
featureFlags: new FeatureFlags({allowCaseFunction: false})
});
expect(result).not.toBeUndefined();
// Expression completions starting with 'c': contains
const labels = result.map(x => x.label);
expect(labels).not.toContain("case");
expect(labels).toContain("contains");
});
}); });
}); });