Migrate expressions, workflow-parser, and languageservice packages to use proper ESM imports with .js extensions that work with node16 moduleResolution. Changes: - Update tsconfig.build.json in each package to use module: node16 and moduleResolution: node16 - Add .js extensions to all relative import paths (Option B approach) - Fix yaml internal type imports in workflow-parser by defining local types - Add skipLibCheck to handle @types/node compatibility issues - Add TypeScript 5.8.3 override in root package.json - Add ESM migration plan documentation The languageserver package is deferred due to test hang issues that need further investigation. Related #154 - Upgrade moduleResolution from node to node16 or nodenext Related #110 - Published ESM code has imports without file extensions Related #64 - expressions: ERR_MODULE_NOT_FOUND attempting to run example Related #146 - Can not import @actions/workflow-parser Test results: - expressions: 1068 tests passed - workflow-parser: 292 tests passed - languageservice: 452 tests passed * docs: update ESM migration plan with findings - Update languageserver blocker: vscode-languageserver v8.0.2 lacks ESM exports (not a test hang issue) - Document that Option B (manual .js extensions) was chosen over Option A due to ts-jest compatibility issues - Add workaround for yaml package internal types (LinePos, NodeBase) - Update migration status table with accurate reason for deferral - Add skipLibCheck note for @types/node compatibility
127 lines
5.4 KiB
TypeScript
127 lines
5.4 KiB
TypeScript
import {data} from "@actions/expressions";
|
|
import {Job} from "@actions/workflow-parser/model/workflow-template";
|
|
import {BooleanToken} from "@actions/workflow-parser/templates/tokens/boolean-token";
|
|
import {MappingToken} from "@actions/workflow-parser/templates/tokens/mapping-token";
|
|
import {NumberToken} from "@actions/workflow-parser/templates/tokens/number-token";
|
|
import {StringToken} from "@actions/workflow-parser/templates/tokens/string-token";
|
|
import {TemplateToken} from "@actions/workflow-parser/templates/tokens/template-token";
|
|
import {WorkflowContext} from "../context/workflow-context.js";
|
|
import {getStrategyContext} from "./strategy.js";
|
|
|
|
function stringToToken(value: string) {
|
|
return new StringToken(undefined, undefined, value, undefined);
|
|
}
|
|
|
|
function boolToToken(value: boolean) {
|
|
return new BooleanToken(undefined, undefined, value, undefined);
|
|
}
|
|
|
|
function numberToToken(value: number) {
|
|
return new NumberToken(undefined, undefined, value, undefined);
|
|
}
|
|
|
|
function contextFromStrategy(strategy?: TemplateToken) {
|
|
return {
|
|
job: {
|
|
strategy: strategy
|
|
}
|
|
} as WorkflowContext;
|
|
}
|
|
|
|
describe("strategy context", () => {
|
|
describe("no strategy defined", () => {
|
|
it("returns defaults when job is undefined", () => {
|
|
const workflowContext = {} as WorkflowContext;
|
|
|
|
const context = getStrategyContext(workflowContext);
|
|
|
|
expect(context.get("fail-fast")).toEqual(new data.BooleanData(true));
|
|
expect(context.get("job-index")).toEqual(new data.NumberData(0));
|
|
expect(context.get("job-total")).toEqual(new data.NumberData(1));
|
|
expect(context.get("max-parallel")).toEqual(new data.NumberData(1));
|
|
});
|
|
|
|
it("returns defaults when strategy is undefined", () => {
|
|
const job = {} as Job;
|
|
const workflowContext = {job} as WorkflowContext;
|
|
|
|
const context = getStrategyContext(workflowContext);
|
|
|
|
expect(context.get("fail-fast")).toEqual(new data.BooleanData(true));
|
|
expect(context.get("job-index")).toEqual(new data.NumberData(0));
|
|
expect(context.get("job-total")).toEqual(new data.NumberData(1));
|
|
expect(context.get("max-parallel")).toEqual(new data.NumberData(1));
|
|
});
|
|
|
|
it("returns defaults when strategy is not a mapping", () => {
|
|
const workflowContext = contextFromStrategy(stringToToken("hello"));
|
|
|
|
const context = getStrategyContext(workflowContext);
|
|
|
|
expect(context.get("fail-fast")).toEqual(new data.BooleanData(true));
|
|
expect(context.get("job-index")).toEqual(new data.NumberData(0));
|
|
expect(context.get("job-total")).toEqual(new data.NumberData(1));
|
|
expect(context.get("max-parallel")).toEqual(new data.NumberData(1));
|
|
});
|
|
});
|
|
|
|
describe("strategy defined with partial properties", () => {
|
|
it("uses specified fail-fast, defaults for others", () => {
|
|
const strategy = new MappingToken(undefined, undefined, undefined);
|
|
strategy.add(stringToToken("fail-fast"), boolToToken(false));
|
|
const workflowContext = contextFromStrategy(strategy);
|
|
|
|
const context = getStrategyContext(workflowContext);
|
|
|
|
expect(context.get("fail-fast")).toEqual(new data.BooleanData(false));
|
|
expect(context.get("job-index")).toEqual(new data.NumberData(0));
|
|
expect(context.get("job-total")).toEqual(new data.NumberData(1));
|
|
expect(context.get("max-parallel")).toEqual(new data.NumberData(1));
|
|
});
|
|
|
|
it("uses specified max-parallel, defaults for others", () => {
|
|
const strategy = new MappingToken(undefined, undefined, undefined);
|
|
strategy.add(stringToToken("max-parallel"), numberToToken(5));
|
|
const workflowContext = contextFromStrategy(strategy);
|
|
|
|
const context = getStrategyContext(workflowContext);
|
|
|
|
expect(context.get("fail-fast")).toEqual(new data.BooleanData(true));
|
|
expect(context.get("job-index")).toEqual(new data.NumberData(0));
|
|
expect(context.get("job-total")).toEqual(new data.NumberData(1));
|
|
expect(context.get("max-parallel")).toEqual(new data.NumberData(5));
|
|
});
|
|
|
|
it("only has matrix defined, all strategy properties use defaults", () => {
|
|
const strategy = new MappingToken(undefined, undefined, undefined);
|
|
const matrix = new MappingToken(undefined, undefined, undefined);
|
|
strategy.add(stringToToken("matrix"), matrix);
|
|
const workflowContext = contextFromStrategy(strategy);
|
|
|
|
const context = getStrategyContext(workflowContext);
|
|
|
|
expect(context.get("fail-fast")).toEqual(new data.BooleanData(true));
|
|
expect(context.get("job-index")).toEqual(new data.NumberData(0));
|
|
expect(context.get("job-total")).toEqual(new data.NumberData(1));
|
|
expect(context.get("max-parallel")).toEqual(new data.NumberData(1));
|
|
});
|
|
});
|
|
|
|
describe("strategy with all properties defined", () => {
|
|
it("uses all specified values", () => {
|
|
const strategy = new MappingToken(undefined, undefined, undefined);
|
|
strategy.add(stringToToken("fail-fast"), boolToToken(false));
|
|
strategy.add(stringToToken("max-parallel"), numberToToken(3));
|
|
const workflowContext = contextFromStrategy(strategy);
|
|
|
|
const context = getStrategyContext(workflowContext);
|
|
|
|
expect(context.get("fail-fast")).toEqual(new data.BooleanData(false));
|
|
// job-index and job-total are runtime values, not specified in YAML
|
|
expect(context.get("job-index")).toEqual(new data.NumberData(0));
|
|
expect(context.get("job-total")).toEqual(new data.NumberData(1));
|
|
expect(context.get("max-parallel")).toEqual(new data.NumberData(3));
|
|
});
|
|
});
|
|
});
|