module TypeA2TypeB;
create b : TypeB from a : TypeA;

rule RootA2RootB {
	from
		rtA : TypeA!RootA
	to
		rtB : TypeB!RootB (
			defs <- rtA.elms->iterate(e; res : Set(TypeA!ElementA) = Set {} |
				if (res->collect(f | f.name)->includes(e.name)) then
					res
				else
					res->including(e)
				endif
				)-- here we keep only one element of each name value
				->collect(e | thisModule.Definition(e)),
				-- then we create a DefinitionB from each selected element
			elms <- rtA.elms
		)
}

lazy rule Definition {
	from
		s : TypeA!ElementA
	to
		t : TypeB!DefinitionB(
			name <- s.name
		)
}

helper def: nameToAssignHistory : Sequence(TupleType(e : TypeB!ElementB, s : String)) =
	Sequence {};

rule NameToAssign (e : TypeB!ElementB, s : String) {
	do {
		thisModule.nameToAssignHistory <- thisModule.nameToAssignHistory->append(Tuple {e = e, s = s});
	}
}

rule Element {
	from
		s : TypeA!ElementA
	to
		t : TypeB!ElementB(
		)
	do {
		-- The corresponding name for the current ElementB is added in the map.
		-- This map will be used at the end of the transformation to create a link between ElementB and DefinitionB
		thisModule.NameToAssign(t, s.name);
	}
}

-- execute delayed actions
endpoint rule EndRule() {
	do {
		for(dta in thisModule.nameToAssignHistory) {
			-- We create a link between an ElementB and the corresponding DefinitionB
			dta.e.definition <- TypeB!DefinitionB.allInstancesFrom('b')->any(e | e.name = dta.s);
		}
	}
}
