I was thinking about this as well recently. Here's what I came up with:
function convertRepeaterPageToPage($repeaterPage, $newParent, $newTemplate, $newStatus) {
// store for cleanup
$forPage = $repeaterPage->getForPage();
$forField = $repeaterPage->getForField();
// convert
$repeaterPage->set('parent_id', $newParent->id);
$repeaterPage->set('templates_id', $newTemplate->id);
$repeaterPage->set('status', $newStatus);
$repeaterPage->set('published', time()); // make this adjustable as well?
$repeaterPage->save(['noHooks'=>true]);
// cleanup
$forPage->save($forField, ['noHooks'=>true]);
return $repeaterPage;
}
Note: It should be improved to make sure what's provided in the arguments is valid. Also maybe have the ability to set the 'name' field of the page as well instead of preserving the auto-generated one that a repeater item gets assigned. Also maybe use types for the arguments.
---
Example: Let's say you have a repeater field called 'books'. Then you decide one day that it would be better that they existed as regular pages instead of repeater pages. Therefore, you would create a new template called 'book' making sure it has the same fields as the repeater fields, then do this:
foreach($pages->get('/path/to/page/')->books as $book) {
convertRepeaterPageToPage($book, wire('pages')->get('/foo/'), 'book', 1);
}