Best JavaScript code snippet using ts-auto-mock
vertexAiCompiler.ts
Source:vertexAiCompiler.ts
1/**2 * @license3 * Copyright 2021 Alexey Volkov4 * SPDX-License-Identifier: Apache-2.05 * @author Alexey Volkov <alexey.volkov+oss@ark-kun.com>6 * @copyright 2021 Alexey Volkov <alexey.volkov+oss@ark-kun.com>7 */8import {9 ArgumentType,10 ComponentSpec,11 StringOrPlaceholder,12 TypeSpecType,13 isContainerImplementation,14 isGraphImplementation,15 InputSpec,16} from "../componentSpec";17import * as vertex from "./vertexPipelineSpec";18// # How to handle I/O:19// Rules (might have exceptions)20// output = output artifact21// inputValue => input parameter22// inputPath => input artifact23// # Fixing conflicts:24// 1) Artifact (may only come from task output) is consumed as value.25// Solution 1) (implemented): Change input from parameter to artifact and use the input.artifact.value placeholder.26// Cons: The downstream component input definitions depend on arguments. (Some inputs are changed from parameter to artifact.)27// Solution 2): Add parameter output (with the same name as the artifact output) to the upstream component. The paths should be the same, so a single file will be treated as both parameter and output.28// Cons: The upstream component output definitions depend on downstream consumption style. (Although parameter outputs are added, not changed.)29// Solution 3): Insert a "Downloader" task between upstream and downstream.30// Cons: Extra container task31// 2) Parameter (pipeline input or constant value) is consumed as artifact (as file).32// Solution 1): Insert a "Uploader" task to convert parameter to artifact.33// Cons: Extra container task34const sanitizePipelineInfoName = (pipelineContextName: string) => {35 return pipelineContextName.toLowerCase().replace(/\W/, "-");36};37type ResolvedCommandLineAndArgs = {38 command?: string[];39 args?: string[];40 inputsConsumedAsParameter: Set<string>;41 inputsConsumedAsArtifact: Set<string>;42};43const resolveCommandLine = (44 componentSpec: ComponentSpec,45 taskArguments: Record<string, ArgumentType>,46 inputsThatHaveParameterArguments: Set<string>47): ResolvedCommandLineAndArgs => {48 if (!isContainerImplementation(componentSpec.implementation)) {49 throw Error("resolveCommandLine only supports container components");50 }51 const containerSpec = componentSpec.implementation.container;52 const inputsConsumedAsParameter = new Set<string>();53 const inputsConsumedAsArtifact = new Set<string>();54 const convertArg = (arg: StringOrPlaceholder): string[] => {55 if (typeof arg == "string") {56 return [arg];57 } else if ("inputValue" in arg) {58 const inputName = arg.inputValue;59 if (!inputsThatHaveParameterArguments.has(inputName)) {60 // ! Important details:61 // In this branch, the argument comes from task output (or graph input with artifact argument).62 // All outputs are artifacts by default, so this argument is an artifact argument.63 // We can either try to change the argument to parameter or make the input to be an artifact to solve the conflict.64 // I choose to make the input to be artifact.65 // Adding input name to inputsConsumedAsPath to make the input rendered as an artifact input.66 inputsConsumedAsArtifact.add(inputName);67 return [`{{$.inputs.artifacts['${inputName}'].value}}`];68 } else {69 inputsConsumedAsParameter.add(inputName);70 return [`{{$.inputs.parameters['${inputName}']}}`];71 }72 } else if ("inputPath" in arg) {73 const inputName = arg.inputPath;74 inputsConsumedAsArtifact.add(inputName);75 return [`{{$.inputs.artifacts['${inputName}'].path}}`];76 } else if ("outputPath" in arg) {77 const outputName = arg.outputPath;78 return [`{{$.outputs.artifacts['${outputName}'].path}}`];79 } else if ("if" in arg) {80 const [ifCond, ifThen, ifElse] = [arg.if.cond, arg.if.then, arg.if.else];81 // TODO: Check false values, not just check for true82 let condEvaluatesToTrue = false;83 if (typeof ifCond === "string") {84 condEvaluatesToTrue = ifCond.toLowerCase() === "true";85 } else if (typeof ifCond === "boolean") {86 condEvaluatesToTrue = ifCond;87 } else if ("isPresent" in ifCond) {88 const inputName = ifCond.isPresent;89 condEvaluatesToTrue = inputName in taskArguments;90 } else if ("inputValue" in ifCond) {91 const inputName = ifCond.inputValue;92 if (!(inputName in taskArguments)) {93 condEvaluatesToTrue = false;94 } else {95 const taskArgument = taskArguments[inputName];96 if (typeof taskArgument === "string") {97 condEvaluatesToTrue = taskArgument.toLowerCase() === "true";98 } else {99 throw Error(100 "Using runtime conditions in component command line placeholders is not supported yet."101 );102 }103 }104 } else {105 throw Error("Unexpected condition kind: " + ifCond);106 }107 const unresolvedArgs = condEvaluatesToTrue ? ifThen : ifElse;108 if (unresolvedArgs === undefined) {109 return [];110 }111 return unresolvedArgs.flatMap(convertArg);112 } else if ("concat" in arg) {113 const concatArgs = arg.concat;114 return [concatArgs.flatMap(convertArg).join("")];115 } else {116 throw Error(`Unknown kind of command-line argument: ${arg}`);117 }118 };119 const result = {120 command: containerSpec.command?.flatMap(convertArg),121 args: containerSpec.args?.flatMap(convertArg),122 inputsConsumedAsParameter: inputsConsumedAsParameter,123 inputsConsumedAsArtifact: inputsConsumedAsArtifact,124 };125 return result;126};127const typeSpecToVertexPrimitiveTypeEnum = (128 typeSpec: TypeSpecType | undefined129): vertex.PrimitiveTypeEnum => {130 if (typeof typeSpec === "string") {131 if (["integer"].includes(typeSpec.toLowerCase())) {132 return vertex.PrimitiveTypeEnum.INT;133 }134 if (["float", "double"].includes(typeSpec.toLowerCase())) {135 return vertex.PrimitiveTypeEnum.DOUBLE;136 }137 }138 return vertex.PrimitiveTypeEnum.STRING;139};140const typeSpecToVertexParameterSpec = (141 typeSpec: TypeSpecType | undefined142): vertex.InputParameterSpec => {143 return {144 type: typeSpecToVertexPrimitiveTypeEnum(typeSpec),145 };146};147const typeSpecToVertexArtifactTypeSchema = (148 typeSpec: TypeSpecType | undefined149): vertex.ArtifactTypeSchema => {150 // TODO: Implement better mapping151 const artifactTypeSchema = {152 schemaTitle: "system.Artifact",153 };154 return artifactTypeSchema;155};156const typeSpecToVertexArtifactSpec = (157 typeSpec: TypeSpecType | undefined158): vertex.InputArtifactSpec => {159 return {160 artifactType: typeSpecToVertexArtifactTypeSchema(typeSpec),161 };162};163// const typeSpecToVertexArtifactType(typeSpec: TypeSpecType) => {164// return typeof typeSpec === "string" && ["String", "Integer", "Float", "Double", "Boolean", ]165// }166const stringToMlmdValue = (167 constantString: string,168 primitiveType: vertex.PrimitiveTypeEnum169): vertex.MlmdValue => {170 switch (primitiveType) {171 case vertex.PrimitiveTypeEnum.STRING:172 return {173 stringValue: constantString,174 };175 case vertex.PrimitiveTypeEnum.INT:176 return {177 intValue: parseInt(constantString),178 };179 case vertex.PrimitiveTypeEnum.DOUBLE:180 return {181 doubleValue: parseFloat(constantString),182 };183 default:184 throw Error(`Unknown primitive type ${primitiveType}`);185 }186};187const MAKE_ARTIFACT_COMPONENT_ID = "_make_artifact";188const MAKE_ARTIFACT_EXECUTOR_ID = "_make_artifact";189const MAKE_ARTIFACT_INPUT_NAME = "parameter";190const MAKE_ARTIFACT_OUTPUT_NAME = "artifact";191const buildMakeArtifactTaskSpec = (192 parameterArgumentSpec: vertex.ParameterArgumentSpec193): vertex.PipelineTaskSpec => {194 const taskSpec: vertex.PipelineTaskSpec = {195 componentRef: {196 name: MAKE_ARTIFACT_COMPONENT_ID,197 },198 taskInfo: {199 name: "Make artifact",200 },201 inputs: {202 parameters: {203 [MAKE_ARTIFACT_INPUT_NAME]: parameterArgumentSpec,204 },205 },206 cachingOptions: {207 enableCache: true,208 },209 };210 return taskSpec;211};212const makeArtifactComponentSpec: vertex.ComponentSpec = {213 executorLabel: MAKE_ARTIFACT_EXECUTOR_ID,214 inputDefinitions: {215 parameters: {216 [MAKE_ARTIFACT_INPUT_NAME]: {217 type: vertex.PrimitiveTypeEnum.STRING,218 },219 },220 },221 outputDefinitions: {222 artifacts: {223 [MAKE_ARTIFACT_OUTPUT_NAME]: {224 artifactType: {225 schemaTitle: "system.Artifact",226 },227 },228 },229 },230};231const makeArtifactExecutorSpec: vertex.ExecutorSpec = {232 container: {233 image: "alpine",234 command: [235 "sh",236 "-ec",237 'mkdir -p "$(dirname "$1")"; printf "%s" "$0" > "$1"',238 `{{$.inputs.parameters['${MAKE_ARTIFACT_INPUT_NAME}']}}`,239 `{{$.outputs.artifacts['${MAKE_ARTIFACT_OUTPUT_NAME}'].path}}`,240 ],241 },242};243function buildVertexParameterArgumentSpec(244 taskArgument: ArgumentType | undefined,245 inputSpec: InputSpec246) {247 if (taskArgument === undefined) {248 if (inputSpec.default !== undefined) {249 taskArgument = inputSpec.default;250 } else {251 if (inputSpec.optional === true) {252 // TODO: Decide what the behavior should be253 // throw Error(`Input "${inputSpec.name}" is optional, but command-line still uses it when when it's not present.`);254 console.error(255 `Input "${inputSpec.name}" is optional, but command-line still uses it when when it's not present.`256 );257 taskArgument = "";258 } else {259 throw Error(260 `Argument was not provided for required input "${inputSpec.name}"`261 );262 }263 }264 }265 let result: vertex.ParameterArgumentSpec;266 if (typeof taskArgument === "string") {267 result = {268 runtimeValue: {269 constantValue: stringToMlmdValue(270 taskArgument,271 typeSpecToVertexPrimitiveTypeEnum(inputSpec.type)272 ),273 },274 };275 return result;276 } else if ("graphInput" in taskArgument) {277 result = {278 componentInputParameter: taskArgument.graphInput.inputName,279 };280 return result;281 } else if ("taskOutput" in taskArgument) {282 result = {283 taskOutputParameter: {284 producerTask: taskArgument.taskOutput.taskId,285 outputParameterKey: taskArgument.taskOutput.outputName,286 },287 };288 return result;289 } else {290 throw Error(`Unknown kind of task argument: "${taskArgument}"`);291 }292}293function buildVertexArtifactArgumentSpec(294 taskArgument: ArgumentType | undefined,295 inputSpec: InputSpec,296 upstreamCannotBeArtifact: boolean,297 addMakeArtifactTaskAndGetArtifactArgumentSpec: (298 parameterArgumentSpec: vertex.ParameterArgumentSpec,299 namePrefix?: string300 ) => vertex.ArtifactArgumentSpec301) {302 //if (! (inputName in taskArguments)) {303 if (taskArgument === undefined) {304 // Checking for default value305 if (inputSpec.default !== undefined) {306 taskArgument = inputSpec.default;307 } else {308 if (inputSpec.optional === true) {309 // TODO: Decide what the behavior should be310 // throw Error(`Input "${inputSpec.name}" is optional, but command-line still uses it when when it's not present.`);311 console.error(312 `Input "${inputSpec.name}" is optional, but command-line still uses it when when it's not present.`313 );314 taskArgument = "";315 } else {316 throw Error(317 `Argument was not provided for required input "${inputSpec.name}"`318 );319 }320 }321 }322 let result: vertex.ArtifactArgumentSpec;323 if (typeof taskArgument === "string") {324 const parameterArgumentSpec: vertex.ParameterArgumentSpec = {325 runtimeValue: {326 constantValue: {327 // TODO: Check whether string is always OK here328 stringValue: taskArgument,329 },330 },331 };332 // TODO: Maybe use the taskArgument as part of the name?333 const convertedArtifactArgumentSpec =334 addMakeArtifactTaskAndGetArtifactArgumentSpec(335 parameterArgumentSpec,336 "Make artifact"337 );338 result = convertedArtifactArgumentSpec;339 return result;340 } else if ("graphInput" in taskArgument) {341 // Workaround for root DAG where all inputs must be parameters342 if (upstreamCannotBeArtifact) {343 const parameterArgumentSpec: vertex.ParameterArgumentSpec = {344 componentInputParameter: taskArgument.graphInput.inputName,345 };346 // We only need one task for each pipeline input parameter347 const convertedArtifactArgumentSpec =348 addMakeArtifactTaskAndGetArtifactArgumentSpec(349 parameterArgumentSpec,350 "Make artifact for " + taskArgument.graphInput.inputName351 );352 result = convertedArtifactArgumentSpec;353 } else {354 result = {355 componentInputArtifact: taskArgument.graphInput.inputName,356 };357 }358 return result;359 } else if ("taskOutput" in taskArgument) {360 result = {361 taskOutputArtifact: {362 producerTask: taskArgument.taskOutput.taskId,363 outputArtifactKey: taskArgument.taskOutput.outputName,364 },365 };366 return result;367 } else {368 throw Error(`Unknown kind of task argument: "${taskArgument}"`);369 }370}371const assertDefined = <T>(obj: T | undefined) => {372 if (obj === undefined) {373 throw TypeError("Object is undefined");374 }375 return obj;376};377const transformRecordValues = <T1, T2>(378 record: Record<string, T1>,379 transform: (value: T1) => T2380) =>381 Object.fromEntries(382 Object.entries(record).map(([key, value]) => [key, transform(value)])383 );384function buildVertexComponentSpecFromContainerComponentSpec(385 componentSpec: ComponentSpec,386 taskArguments: Record<string, ArgumentType>,387 inputsThatHaveParameterArguments: Set<string>,388 addExecutorAndGetId: (389 executor: vertex.ExecutorSpec,390 namePrefix?: string | undefined391 ) => string392) {393 if (!isContainerImplementation(componentSpec.implementation)) {394 throw Error("Only container components are supported by this function");395 }396 const containerSpec = componentSpec.implementation.container;397 const resolvedCommandLine = resolveCommandLine(398 componentSpec,399 taskArguments,400 inputsThatHaveParameterArguments401 );402 const vertexExecutorSpec: vertex.ExecutorSpec = {403 container: {404 image: containerSpec.image,405 command: resolvedCommandLine.command,406 args: resolvedCommandLine.args,407 },408 };409 const vertexExecutorId = addExecutorAndGetId(410 vertexExecutorSpec,411 componentSpec.name ?? "Component"412 );413 const inputMap = new Map(414 (componentSpec.inputs ?? []).map((inputSpec) => [inputSpec.name, inputSpec])415 );416 const vertexComponentInputsSpec: vertex.ComponentInputsSpec = {417 parameters: Object.fromEntries(418 Array.from(resolvedCommandLine.inputsConsumedAsParameter.values()).map(419 (inputName) => [420 inputName,421 typeSpecToVertexParameterSpec(inputMap.get(inputName)?.type),422 ]423 )424 ),425 artifacts: Object.fromEntries(426 Array.from(resolvedCommandLine.inputsConsumedAsArtifact.values()).map(427 (inputName) => [428 inputName,429 typeSpecToVertexArtifactSpec(inputMap.get(inputName)?.type),430 ]431 )432 ),433 };434 const vertexComponentOutputsSpec: vertex.ComponentOutputsSpec = {435 parameters: {},436 artifacts: Object.fromEntries(437 (componentSpec.outputs ?? []).map((outputSpec) => [438 outputSpec.name,439 typeSpecToVertexArtifactSpec(outputSpec.type),440 ])441 ),442 };443 const vertexComponentSpec: vertex.ComponentSpec = {444 inputDefinitions: vertexComponentInputsSpec,445 outputDefinitions: vertexComponentOutputsSpec,446 // dag447 executorLabel: vertexExecutorId,448 };449 return vertexComponentSpec;450}451function buildVertexComponentSpecFromGraphComponentSpec(452 componentSpec: ComponentSpec,453 taskArguments: Record<string, ArgumentType>,454 inputsThatHaveParameterArguments: Set<string>,455 addExecutorAndGetId: (456 executor: vertex.ExecutorSpec,457 namePrefix?: string458 ) => string,459 addComponentAndGetId: (460 component: vertex.ComponentSpec,461 namePrefix?: string462 ) => string463) {464 if (!isGraphImplementation(componentSpec.implementation)) {465 throw Error("Only graph components are supported by this function");466 }467 const graphSpec = componentSpec.implementation.graph;468 const inputsConsumedAsParameter = new Set<string>();469 const inputsConsumedAsArtifact = new Set<string>();470 let vertexTasks: Record<string, vertex.PipelineTaskSpec> = {};471 const taskStringToTaskId = new Map<string, string>();472 const addTaskAndGetId = (473 task: vertex.PipelineTaskSpec,474 namePrefix: string = "Task"475 ) => {476 const serializedSpec = JSON.stringify(task);477 const existingId = taskStringToTaskId.get(serializedSpec);478 if (existingId !== undefined) {479 return existingId;480 }481 const usedIds = new Set(Object.keys(vertexTasks));482 const id = makeNameUniqueByAddingIndex(namePrefix, usedIds);483 taskStringToTaskId.set(serializedSpec, id);484 vertexTasks[id] = task;485 return id;486 };487 const addMakeArtifactTaskAndGetArtifactArgumentSpec = (488 parameterArgumentSpec: vertex.ParameterArgumentSpec,489 namePrefix: string = "Make artifact"490 ) => {491 // These system names are expected to not conflict with user task names492 const makeArtifactExecutorId = addExecutorAndGetId(493 makeArtifactExecutorSpec,494 MAKE_ARTIFACT_EXECUTOR_ID495 );496 const makeArtifactComponentSpecCopy = {497 ...makeArtifactComponentSpec,498 executorLabel: makeArtifactExecutorId,499 };500 const makeArtifactComponentsId = addComponentAndGetId(501 makeArtifactComponentSpecCopy,502 MAKE_ARTIFACT_COMPONENT_ID503 );504 const makeArtifactTaskSpec = buildMakeArtifactTaskSpec(505 parameterArgumentSpec506 );507 makeArtifactTaskSpec.componentRef.name = makeArtifactComponentsId;508 const taskId = addTaskAndGetId(makeArtifactTaskSpec, namePrefix);509 const artifactArgumentSpec: vertex.ArtifactArgumentSpec = {510 taskOutputArtifact: {511 producerTask: taskId,512 outputArtifactKey: MAKE_ARTIFACT_OUTPUT_NAME,513 },514 };515 return artifactArgumentSpec;516 };517 for (const [taskId, taskSpec] of Object.entries(graphSpec.tasks)) {518 if (taskSpec.componentRef.spec === undefined) {519 throw Error(`Task "${taskId}" does not have taskSpec.componentRef.spec.`);520 }521 try {522 const vertexTaskSpec = buildVertexTaskSpecFromTaskSpec(523 taskSpec.componentRef.spec,524 taskSpec.arguments ?? {},525 inputsThatHaveParameterArguments,526 addExecutorAndGetId,527 addComponentAndGetId,528 addMakeArtifactTaskAndGetArtifactArgumentSpec529 );530 if (taskId in vertexTasks) {531 throw Error(532 `Task ID "${taskId}" is not unique. This cannot happen (unless user task ID clashes with special task ID).`533 );534 }535 vertexTasks[taskId] = vertexTaskSpec;536 for (const argument of Object.values(537 vertexTaskSpec.inputs?.parameters ?? {}538 )) {539 if (argument.componentInputParameter !== undefined) {540 inputsConsumedAsParameter.add(argument.componentInputParameter);541 }542 }543 for (const argument of Object.values(544 vertexTaskSpec.inputs?.artifacts ?? {}545 )) {546 if ("componentInputArtifact" in argument) {547 inputsConsumedAsArtifact.add(argument.componentInputArtifact);548 }549 }550 } catch (err) {551 if (err instanceof Error) {552 err.message = `Error compiling task ${taskId}: ` + err.message;553 }554 throw err;555 }556 }557 // Sanity checks558 const inputNamesThatAreUsedBothAsParameterAndArtifact = Array.from(559 inputsConsumedAsParameter560 ).filter((x) => inputsConsumedAsArtifact.has(x));561 if (inputNamesThatAreUsedBothAsParameterAndArtifact.length > 0) {562 throw Error(563 `Compiler error: Some inputs are used both as parameter and artifact: "${inputNamesThatAreUsedBothAsParameterAndArtifact}". Please file a bug report.`564 );565 }566 const inputNamesThatAreParametersButAreConsumedAsArtifacts = Array.from(567 inputsThatHaveParameterArguments568 ).filter((x) => inputsConsumedAsArtifact.has(x));569 if (inputNamesThatAreParametersButAreConsumedAsArtifacts.length > 0) {570 throw Error(571 `Compiler error: Some parameter inputs are consumer as artifact: "${inputNamesThatAreParametersButAreConsumedAsArtifacts}". Please file a bug report.`572 );573 }574 const dagOutputArtifactSpecs = transformRecordValues(575 graphSpec.outputValues ?? {},576 (taskOutputArgument) => {577 const result: vertex.DagOutputArtifactSpec = {578 artifactSelectors: [579 {580 producerSubtask: taskOutputArgument.taskOutput.taskId,581 outputArtifactKey: taskOutputArgument.taskOutput.outputName,582 },583 ],584 };585 return result;586 }587 );588 const inputMap = new Map(589 (componentSpec.inputs ?? []).map((inputSpec) => [inputSpec.name, inputSpec])590 );591 const vertexComponentInputsSpec: vertex.ComponentInputsSpec = {592 parameters: Object.fromEntries(593 Array.from(inputsConsumedAsParameter.values()).map((inputName) => [594 inputName,595 typeSpecToVertexParameterSpec(inputMap.get(inputName)?.type),596 ])597 ),598 artifacts: Object.fromEntries(599 Array.from(inputsConsumedAsArtifact.values()).map((inputName) => [600 inputName,601 typeSpecToVertexArtifactSpec(inputMap.get(inputName)?.type),602 ])603 ),604 };605 const vertexComponentOutputsSpec: vertex.ComponentOutputsSpec = {606 // parameters: {},607 artifacts: Object.fromEntries(608 (componentSpec.outputs ?? []).map((outputSpec) => [609 outputSpec.name,610 typeSpecToVertexArtifactSpec(outputSpec.type),611 ])612 ),613 };614 const vertexComponentSpec: vertex.ComponentSpec = {615 inputDefinitions: vertexComponentInputsSpec,616 outputDefinitions: vertexComponentOutputsSpec,617 dag: {618 tasks: vertexTasks,619 outputs: {620 artifacts: dagOutputArtifactSpecs,621 // parameters: {},622 },623 },624 };625 return vertexComponentSpec;626}627function buildVertexComponentSpecFromComponentSpec(628 componentSpec: ComponentSpec,629 taskArguments: Record<string, ArgumentType>,630 inputsThatHaveParameterArguments: Set<string>,631 addExecutorAndGetId: (632 executor: vertex.ExecutorSpec,633 namePrefix?: string634 ) => string,635 addComponentAndGetId: (636 component: vertex.ComponentSpec,637 namePrefix?: string638 ) => string639) {640 if (isContainerImplementation(componentSpec.implementation)) {641 return buildVertexComponentSpecFromContainerComponentSpec(642 componentSpec,643 taskArguments,644 inputsThatHaveParameterArguments,645 addExecutorAndGetId646 );647 } else if (isGraphImplementation(componentSpec.implementation)) {648 return buildVertexComponentSpecFromGraphComponentSpec(649 componentSpec,650 taskArguments,651 inputsThatHaveParameterArguments,652 addExecutorAndGetId,653 addComponentAndGetId654 );655 } else {656 throw Error(657 `Unsupported component implementation kind: ${componentSpec.implementation}`658 );659 }660}661const buildVertexTaskSpecFromTaskSpec = (662 componentSpec: ComponentSpec,663 //passedArgumentNames: string[],664 taskArguments: Record<string, ArgumentType>,665 graphInputsWithParameterArguments: Set<string>,666 addExecutorAndGetId: (667 executor: vertex.ExecutorSpec,668 namePrefix?: string669 ) => string,670 addComponentAndGetId: (671 component: vertex.ComponentSpec,672 namePrefix?: string673 ) => string,674 addMakeArtifactTaskAndGetArtifactArgumentSpec: (675 parameterArgumentSpec: vertex.ParameterArgumentSpec,676 namePrefix?: string677 ) => vertex.ArtifactArgumentSpec678) => {679 // So-called "parameter" arguments can either be constant arguments680 // or come from the arguments to the graph component of the current task.681 // In the current implementation the parameter arguments cannot come from task outputs since all task outputs are artifacts.682 const inputsThatHaveParameterArguments = new Set(683 (componentSpec.inputs ?? [])684 .map((inputSpec) => inputSpec.name)685 .filter((inputName) => {686 const taskArgument = taskArguments[inputName];687 if (taskArgument === undefined) {688 // Missing arguments fall back to default values which are constant strings which are parameters.689 return true;690 }691 if (typeof taskArgument === "string") {692 return true;693 }694 if ("graphInput" in taskArgument) {695 if (696 graphInputsWithParameterArguments.has(697 taskArgument.graphInput.inputName698 )699 ) {700 return true;701 }702 }703 return false;704 })705 );706 const inputMap = new Map(707 (componentSpec.inputs ?? []).map((inputSpec) => [inputSpec.name, inputSpec])708 );709 const vertexComponentSpec: vertex.ComponentSpec =710 buildVertexComponentSpecFromComponentSpec(711 componentSpec,712 taskArguments,713 inputsThatHaveParameterArguments,714 addExecutorAndGetId,715 addComponentAndGetId716 );717 const vertexComponentId = addComponentAndGetId(718 vertexComponentSpec,719 componentSpec.name ?? "Component"720 );721 const vertexTaskParameterArguments = Object.fromEntries(722 Object.keys(vertexComponentSpec.inputDefinitions?.parameters ?? {}).map(723 (inputName) => [724 inputName,725 buildVertexParameterArgumentSpec(726 taskArguments[inputName],727 assertDefined(inputMap.get(inputName))728 ),729 ]730 )731 );732 const vertexTaskArtifactArguments = Object.fromEntries(733 Object.keys(vertexComponentSpec.inputDefinitions?.artifacts ?? {}).map(734 (inputName) => [735 inputName,736 buildVertexArtifactArgumentSpec(737 taskArguments[inputName],738 assertDefined(inputMap.get(inputName)),739 inputsThatHaveParameterArguments.has(inputName),740 addMakeArtifactTaskAndGetArtifactArgumentSpec741 ),742 ]743 )744 );745 const vertexTaskSpec: vertex.PipelineTaskSpec = {746 taskInfo: {747 // This is the task display name, not an ID748 name: componentSpec.name ?? "Component",749 },750 inputs: {751 parameters: vertexTaskParameterArguments,752 artifacts: vertexTaskArtifactArguments,753 },754 // dependent_tasks: [],755 cachingOptions: {756 enableCache: true,757 },758 componentRef: {759 name: vertexComponentId,760 },761 // triggerPolicy: {762 // condition: "...",763 // strategy: "ALL_UPSTREAM_TASKS_SUCCEEDED",764 // },765 // iterator: {766 // artifactIterator: {...},767 // parameterIterator: {...},768 // },769 };770 return vertexTaskSpec;771};772const makeNameUniqueByAddingIndex = (773 name: string,774 existingNames: Set<string>775): string => {776 let finalName = name;777 let index = 1;778 while (existingNames.has(finalName)) {779 index++;780 finalName = name + " " + index.toString();781 }782 return finalName;783};784export const graphComponentSpecToVertexPipelineSpec = (785 componentSpec: ComponentSpec,786 pipelineContextName = "pipeline"787) => {788 let vertexExecutors: Record<string, vertex.ExecutorSpec> = {};789 const executorStringToExecutorId = new Map<string, string>();790 let vertexComponents: Record<string, vertex.ComponentSpec> = {};791 const componentStringToComponentId = new Map<string, string>();792 const addExecutorAndGetId = (793 executor: vertex.ExecutorSpec,794 namePrefix: string = "Executor"795 ) => {796 const serializedSpec = JSON.stringify(executor);797 const existingId = executorStringToExecutorId.get(serializedSpec);798 if (existingId !== undefined) {799 return existingId;800 }801 const usedIds = new Set(Object.keys(vertexExecutors));802 const id = makeNameUniqueByAddingIndex(namePrefix, usedIds);803 executorStringToExecutorId.set(serializedSpec, id);804 vertexExecutors[id] = executor;805 return id;806 };807 const addComponentAndGetId = (808 component: vertex.ComponentSpec,809 namePrefix: string = "Component"810 ) => {811 const serializedSpec = JSON.stringify(component);812 const existingId = componentStringToComponentId.get(serializedSpec);813 if (existingId !== undefined) {814 return existingId;815 }816 const usedIds = new Set(Object.keys(vertexComponents));817 const id = makeNameUniqueByAddingIndex(namePrefix, usedIds);818 componentStringToComponentId.set(serializedSpec, id);819 vertexComponents[id] = component;820 return id;821 };822 // All root graph inputs are parameters823 const graphInputsWithParameterArguments = new Set(824 (componentSpec.inputs ?? []).map((inputSpec) => inputSpec.name)825 );826 const pipelineArguments: Record<string, ArgumentType> = Object.fromEntries(827 (componentSpec.inputs ?? []).map((inputSpec) => {828 const argument: ArgumentType = {829 graphInput: { inputName: inputSpec.name },830 };831 return [inputSpec.name, argument];832 })833 );834 const pipelineComponentSpec = buildVertexComponentSpecFromComponentSpec(835 componentSpec,836 pipelineArguments,837 graphInputsWithParameterArguments,838 addExecutorAndGetId,839 addComponentAndGetId840 );841 const vertexPipelineSpec: vertex.PipelineSpec = {842 pipelineInfo: {843 name: sanitizePipelineInfoName(pipelineContextName),844 },845 sdkVersion: "Cloud-Pipelines",846 schemaVersion: "2.0.0",847 deploymentSpec: {848 executors: vertexExecutors,849 },850 components: vertexComponents,851 root: pipelineComponentSpec,852 };853 return vertexPipelineSpec;854};855export const generateVertexPipelineJobFromGraphComponent = (856 componentSpec: ComponentSpec,857 gcsOutputDirectory: string,858 pipelineArguments?: Map<string, string>,859 pipelineContextName = "pipeline"860) => {861 // The pipelineContextName affects caching862 const pipelineSpec = graphComponentSpecToVertexPipelineSpec(863 componentSpec,864 pipelineContextName865 );866 const inputParameterDefinitions =867 (pipelineSpec.root.inputDefinitions ?? {}).parameters ?? {};868 let convertedPipelineArguments: Record<string, any> = {};869 if (pipelineArguments !== undefined) {870 for (const [key, value] of Array.from(pipelineArguments.entries())) {871 convertedPipelineArguments[key] = stringToMlmdValue(872 value,873 inputParameterDefinitions[key].type874 );875 }876 }877 const pipelineJob: vertex.PipelineJob = {878 // name: "<>",879 // Does not show up in the UX880 displayName: componentSpec.name ?? "Pipeline",881 // labels: {},882 runtimeConfig: {883 parameters: convertedPipelineArguments,884 gcsOutputDirectory: gcsOutputDirectory,885 },886 pipelineSpec: pipelineSpec,887 // encryptionSpec: {},888 // serviceAccount: "<>",889 // network: {},890 };891 return pipelineJob;...
process.js
Source:process.js
1function ProcessService(process) {2 const argumentMap = getArguments();3 return {4 getArgument(argumentName) {5 const argument = argumentMap[argumentName];6 return argument === undefined ? '' : argument;7 },8 ensureArgumentsValidity(acceptedArguments) {9 const acceptedArgumentsMap = {};10 for (let i = 0; i < acceptedArguments.length; i++) {11 acceptedArgumentsMap[acceptedArguments[i]] = true;12 }13 const passedArgumentNames = Object.keys(argumentMap);14 for (let i = 0; i < passedArgumentNames.length; i++) {15 if (!acceptedArgumentsMap[passedArgumentNames[i]]) {16 throw new Error(`Argument ${passedArgumentNames[i]} is not accepted, only available arguments are ${acceptedArguments.join(', ')}`)17 }18 }19 },20 getEnvironmentValue(envKey) {21 const environmentVariables = process.env;22 return convertToBooleanWhenTrueOrFalse(environmentVariables[envKey]);23 }24 };25 function convertToBooleanWhenTrueOrFalse(maybeBoolean) {26 if (maybeBoolean === 'true') {27 return true;28 }29 if (maybeBoolean === 'false') {30 return false;31 }32 return maybeBoolean;33 }34 function getArguments() {35 const processArguments = process.argv.slice(2);36 const map = {};37 for(let i = 0; i < processArguments.length; i++) {38 const values = processArguments[i].split('=');39 map[values[0]] = values[1];40 }41 return map;42 }43}...
Using AI Code Generation
1import { passedArgumentNames } from 'ts-auto-mock/extension';2export function test1() {3 const args = passedArgumentNames();4 console.log(args);5}6import { passedArgumentNames } from 'ts-auto-mock/extension';7export function test2() {8 const args = passedArgumentNames();9 console.log(args);10}11import { passedArgumentNames } from 'ts-auto-mock/extension';12export function test3() {13 const args = passedArgumentNames();14 console.log(args);15}16import { passedArgumentNames } from 'ts-auto-mock/extension';17export function test4() {18 const args = passedArgumentNames();19 console.log(args);20}21import { passedArgumentNames } from 'ts-auto-mock/extension';22export function test5() {23 const args = passedArgumentNames();24 console.log(args);25}26import { passedArgumentNames } from 'ts-auto-mock/extension';27export function test6() {28 const args = passedArgumentNames();29 console.log(args);30}31import { passedArgumentNames } from 'ts-auto-mock/extension';32export function test7() {33 const args = passedArgumentNames();34 console.log(args);35}36import { passedArgumentNames } from 'ts-auto-mock/extension';37export function test8() {38 const args = passedArgumentNames();39 console.log(args);40}41import { passedArgumentNames } from 'ts-auto-mock/extension';42export function test9() {43 const args = passedArgumentNames();44 console.log(args);45}
Using AI Code Generation
1const passedArgumentNames = require('ts-auto-mock/argumentNames');2const passedArgumentNames = require('ts-auto-mock/argumentNames');3const { passedArgumentNames } = require('ts-auto-mock/argumentNames');4const passedArgumentNames = require('ts-auto-mock/argumentNames');5const { passedArgumentNames } = require('ts-auto-mock/argumentNames');6`mock<T>(options?: Options): T;`
Using AI Code Generation
1const { passedArgumentNames } = require('ts-auto-mock');2const { mock } = require('ts-auto-mock/extension');3const { expect } = require('chai');4describe('passedArgumentNames', () => {5 it('should return the name of the argument passed', () => {6 const result = passedArgumentNames(mock<TestClass>());7 expect(result).to.deep.equal(['test', 'test2']);8 });9});10import { passedArgumentNames } from 'ts-auto-mock';11import { mock } from 'ts-auto-mock/extension';12describe('passedArgumentNames', () => {13 it('should return the name of the argument passed', () => {14 const result = passedArgumentNames(mock<TestClass>());15 expect(result).to.deep.equal(['test', 'test2']);16 });17});
Using AI Code Generation
1const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;2const argumentNames = passedArgumentNames();3const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;4const argumentNames = passedArgumentNames();5const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;6const argumentNames = passedArgumentNames();7const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;8const argumentNames = passedArgumentNames();9const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;10const argumentNames = passedArgumentNames();11const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;12const argumentNames = passedArgumentNames();13const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;14const argumentNames = passedArgumentNames();15const passedArgumentNames = require('ts-auto-mock/extension').passedArgumentNames;16const argumentNames = passedArgumentNames();
Using AI Code Generation
1const tsAutoMock = require('ts-auto-mock');2const { passedArgumentNames } = tsAutoMock;3const functionToTest = (arg1, arg2) => {4 const names = passedArgumentNames();5};6functionToTest('foo', 'bar');7const tsAutoMock = require('ts-auto-mock');8const { passedArgumentNames } = tsAutoMock;9const functionToTest = (arg1, arg2) => {10 const names = passedArgumentNames();11};12functionToTest('foo', 'bar');13const tsAutoMock = require('ts-auto-mock');14const { passedArgumentNames } = tsAutoMock;15const functionToTest = (arg1, arg2) => {16 const names = passedArgumentNames();17};18functionToTest('foo', 'bar');19const tsAutoMock = require('ts-auto-mock');20const { passedArgumentNames } = tsAutoMock;21const functionToTest = (arg1, arg2) => {22 const names = passedArgumentNames();23};24functionToTest('foo', 'bar');25const tsAutoMock = require('ts-auto-mock');26const { passedArgumentNames } = tsAutoMock;27const functionToTest = (arg1, arg2) => {28 const names = passedArgumentNames();29};30functionToTest('foo', 'bar');31const tsAutoMock = require('ts-auto-mock');32const { passedArgumentNames } = tsAutoMock;33const functionToTest = (arg1, arg2) => {34 const names = passedArgumentNames();35};36functionToTest('foo', 'bar');
Using AI Code Generation
1const mock = createMock<InterfaceToMock>();2const passedArguments = mock.method.passedArgumentNames();3const passedArguments = mock.method.passedArgumentNames(0);4const passedArguments = mock.method.passedArgumentNames(0, 1);5const passedArguments = mock.method.passedArgumentNames(0, 1, 2);6const mock = createMock<InterfaceToMock>();7const passedArguments = mock.method.passedArgumentNames();8const passedArguments = mock.method.passedArgumentNames(0);9const passedArguments = mock.method.passedArgumentNames(0, 1);10const passedArguments = mock.method.passedArgumentNames(0, 1, 2);11const mock = createMock<InterfaceToMock>();12const passedArguments = mock.method.passedArgumentNames();13const passedArguments = mock.method.passedArgumentNames(0);14const passedArguments = mock.method.passedArgumentNames(0, 1);15const passedArguments = mock.method.passedArgumentNames(0, 1, 2);16const mock = createMock<InterfaceToMock>();17const passedArguments = mock.method.passedArgumentNames();18const passedArguments = mock.method.passedArgumentNames(0);19const passedArguments = mock.method.passedArgumentNames(0, 1);20const passedArguments = mock.method.passedArgumentNames(0, 1, 2);21const mock = createMock<InterfaceToMock>();22const passedArguments = mock.method.passedArgumentNames();23const passedArguments = mock.method.passedArgumentNames(0);24const passedArguments = mock.method.passedArgumentNames(0, 1);25const passedArguments = mock.method.passedArgumentNames(0, 1, 2);26const mock = createMock<InterfaceToMock>();27const passedArguments = mock.method.passedArgumentNames();28const passedArguments = mock.method.passedArgumentNames(0);
Learn to execute automation testing from scratch with LambdaTest Learning Hub. Right from setting up the prerequisites to run your first automation test, to following best practices and diving deeper into advanced test scenarios. LambdaTest Learning Hubs compile a list of step-by-step guides to help you be proficient with different test automation frameworks i.e. Selenium, Cypress, TestNG etc.
You could also refer to video tutorials over LambdaTest YouTube channel to get step by step demonstration from industry experts.
Get 100 minutes of automation test minutes FREE!!