So thanks to your help, plus a for-in loop I learnt about from the following post:
How to generate CSS with loop in less
I now have:
.for(@list, @code) {
& {
.loop(@i:1) when (@i =< length(@list)) {
@value: extract(@list, @i);
@code();
.loop(@i + 1);
}
.loop();
}
}
.role-varients(@orgType, @variants, @props, @type:child){
.for(@variants, {
& when (@type = append) {
&.@{orgType}.security_class_@{value} {
@props();
}
}
& when not (@type = append) {
.@{orgType}.security_class_@{value} {
@props();
}
}
});
}
@admin-roles: admin, admin_manager, admin_user, admin_manager_user;
@manager-roles: manager, admin_manager, manager_user, admin_manager_user;
@user-roles: user, admin_user, manager_user, admin_manager_user;
&.service_provider{
&.admin{
.role-varients(service_provider, @admin-roles, {display: block;});
th{
.role-varients(service_provider, @admin-roles, {display: table-cell;}, append);
}
button{
.role-varients(service_provider, @admin-roles, {display: inline-block;}, append);
}
}
&.manager{
.role-varients(service_provider, @manager-roles, {display: block;});
th{
.role-varients(service_provider, @manager-roles, {display: table-cell;}, append);
}
button{
.role-varients(service_provider, @manager-roles, {display: inline-block;}, append);
}
}
&.user{
.role-varients(service_provider, @user-roles, {display: block;});
th{
.role-varients(service_provider, @user-roles, {display: table-cell;}, append);
}
button{
.role-varients(service_provider, @user-roles, {display: inline-block;}, append);
}
}
}
&.client{
&.admin{
.role-varients(client, @admin-roles, {display: block;});
th{
.role-varients(client, @admin-roles, {display: table-cell;}, append);
}
button{
.role-varients(client, @admin-roles, {display: inline-block;}, append);
}
}
&.manager{
.role-varients(client, @manager-roles, {display: block;});
th{
.role-varients(client, @manager-roles, {display: table-cell;}, append);
}
button{
.role-varients(client, @manager-roles, {display: inline-block;}, append);
}
}
&.user{
.role-varients(client, @user-roles, {display: block;});
th{
.role-varients(client, @user-roles, {display: table-cell;}, append);
}
button{
.role-varients(client, @user-roles, {display: inline-block;}, append);
}
}
}
&.vendor{
&.admin{
.role-varients(vendor, @admin-roles, {display: block;});
th{
.role-varients(vendor, @admin-roles, {display: table-cell;}, append);
}
button{
.role-varients(vendor, @admin-roles, {display: inline-block;}, append);
}
}
&.manager{
.role-varients(vendor, @manager-roles, {display: block;});
th{
.role-varients(vendor, @manager-roles, {display: table-cell;}, append);
}
button{
.role-varients(vendor, @manager-roles, {display: inline-block;}, append);
}
}
&.user{
.role-varients(vendor, @user-roles, {display: block;});
th{
.role-varients(vendor, @user-roles, {display: table-cell;}, append);
}
button{
.role-varients(vendor, @user-roles, {display: inline-block;}, append);
}
}
}
I would use another for loop to handle the 3 main blocks [service_provider, client, vendor] but where I am using .@{value} I guess the scope is broken from having a loop within a loop and it does not produce the expected results.
Although the above still seems long, it is definitely better than writing each rule manually.
My solution came about thanks to Harry's input so I guess I should mark his answer as correct? Thanks again all ;)