You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 

293 lines
16 KiB

#!/usr/bin/env node
/**
* Migration script to update state references in +page.svelte
* This helps automate the bulk replacement of old state variable references
* with the new nested state structure.
*/
import { readFileSync, writeFileSync } from 'fs';
import { fileURLToPath } from 'url';
import { dirname, join } from 'path';
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
const rootDir = join(__dirname, '..');
const targetFile = join(rootDir, 'src/routes/repos/[npub]/[repo]/+page.svelte');
// Migration mappings: old reference -> new reference
const migrations = [
// Loading states
{ pattern: /\bloading\b/g, replacement: 'state.loading.main' },
{ pattern: /\bloadingReadme\b/g, replacement: 'state.loading.readme' },
{ pattern: /\bloadingCommits\b/g, replacement: 'state.loading.commits' },
{ pattern: /\bloadingIssues\b/g, replacement: 'state.loading.issues' },
{ pattern: /\bloadingIssueReplies\b/g, replacement: 'state.loading.issueReplies' },
{ pattern: /\bloadingPRs\b/g, replacement: 'state.loading.prs' },
{ pattern: /\bloadingPatches\b/g, replacement: 'state.loading.patches' },
{ pattern: /\bloadingPatchHighlights\b/g, replacement: 'state.loading.patchHighlights' },
{ pattern: /\bloadingDocs\b/g, replacement: 'state.loading.docs' },
{ pattern: /\bloadingDiscussions\b/g, replacement: 'state.loading.discussions' },
{ pattern: /\bloadingReleases\b/g, replacement: 'state.loading.releases' },
{ pattern: /\bloadingCodeSearch\b/g, replacement: 'state.loading.codeSearch' },
{ pattern: /\bloadingBookmark\b/g, replacement: 'state.loading.bookmark' },
{ pattern: /\bloadingMaintainerStatus\b/g, replacement: 'state.loading.maintainerStatus' },
{ pattern: /\bloadingMaintainers\b/g, replacement: 'state.loading.maintainers' },
{ pattern: /\bloadingReachability\b/g, replacement: 'state.loading.reachability' },
{ pattern: /\bloadingVerification\b/g, replacement: 'state.loading.verification' },
// UI state
{ pattern: /\bactiveTab\b/g, replacement: 'state.ui.activeTab' },
{ pattern: /\bshowRepoMenu\b/g, replacement: 'state.ui.showRepoMenu' },
{ pattern: /\bshowFileListOnMobile\b/g, replacement: 'state.ui.showFileListOnMobile' },
{ pattern: /\bshowLeftPanelOnMobile\b/g, replacement: 'state.ui.showLeftPanelOnMobile' },
{ pattern: /\bwordWrap\b/g, replacement: 'state.ui.wordWrap' },
{ pattern: /\bexpandedThreads\b/g, replacement: 'state.ui.expandedThreads' },
// User state
{ pattern: /\buserPubkey\b/g, replacement: 'state.user.pubkey' },
{ pattern: /\buserPubkeyHex\b/g, replacement: 'state.user.pubkeyHex' },
// Files
{ pattern: /\bfiles\b/g, replacement: 'state.files.list' },
{ pattern: /\bcurrentPath\b/g, replacement: 'state.files.currentPath' },
{ pattern: /\bcurrentFile\b/g, replacement: 'state.files.currentFile' },
{ pattern: /\bfileContent\b/g, replacement: 'state.files.content' },
{ pattern: /\bfileLanguage\b/g, replacement: 'state.files.language' },
{ pattern: /\beditedContent\b/g, replacement: 'state.files.editedContent' },
{ pattern: /\bhasChanges\b/g, replacement: 'state.files.hasChanges' },
{ pattern: /\bpathStack\b/g, replacement: 'state.files.pathStack' },
// Preview
{ pattern: /\breadmeContent\b/g, replacement: 'state.preview.readme.content' },
{ pattern: /\breadmePath\b/g, replacement: 'state.preview.readme.path' },
{ pattern: /\breadmeIsMarkdown\b/g, replacement: 'state.preview.readme.isMarkdown' },
{ pattern: /\breadmeHtml\b/g, replacement: 'state.preview.readme.html' },
{ pattern: /\bhighlightedFileContent\b/g, replacement: 'state.preview.file.highlightedContent' },
{ pattern: /\bfileHtml\b/g, replacement: 'state.preview.file.html' },
{ pattern: /\bshowFilePreview\b/g, replacement: 'state.preview.file.showPreview' },
{ pattern: /\bcopyingFile\b/g, replacement: 'state.preview.copying' },
{ pattern: /\bisImageFile\b/g, replacement: 'state.preview.file.isImage' },
{ pattern: /\bimageUrl\b/g, replacement: 'state.preview.file.imageUrl' },
// Git
{ pattern: /\bbranches\b/g, replacement: 'state.git.branches' },
{ pattern: /\bcurrentBranch\b/g, replacement: 'state.git.currentBranch' },
{ pattern: /\bdefaultBranch\b/g, replacement: 'state.git.defaultBranch' },
{ pattern: /\bcommits\b/g, replacement: 'state.git.commits' },
{ pattern: /\bselectedCommit\b/g, replacement: 'state.git.selectedCommit' },
{ pattern: /\bshowDiff\b/g, replacement: 'state.git.showDiff' },
{ pattern: /\bdiffData\b/g, replacement: 'state.git.diffData' },
{ pattern: /\bverifyingCommits\b/g, replacement: 'state.git.verifyingCommits' },
{ pattern: /\btags\b/g, replacement: 'state.git.tags' },
{ pattern: /\bselectedTag\b/g, replacement: 'state.git.selectedTag' },
// Forms
{ pattern: /\bnewFileName\b/g, replacement: 'state.forms.file.fileName' },
{ pattern: /\bnewFileContent\b/g, replacement: 'state.forms.file.content' },
{ pattern: /\bnewBranchName\b/g, replacement: 'state.forms.branch.name' },
{ pattern: /\bnewBranchFrom\b/g, replacement: 'state.forms.branch.from' },
{ pattern: /\bdefaultBranchName\b/g, replacement: 'state.forms.branch.defaultName' },
{ pattern: /\bnewTagName\b/g, replacement: 'state.forms.tag.name' },
{ pattern: /\bnewTagMessage\b/g, replacement: 'state.forms.tag.message' },
{ pattern: /\bnewTagRef\b/g, replacement: 'state.forms.tag.ref' },
{ pattern: /\bcommitMessage\b/g, replacement: 'state.forms.commit.message' },
{ pattern: /\bnewIssueSubject\b/g, replacement: 'state.forms.issue.subject' },
{ pattern: /\bnewIssueContent\b/g, replacement: 'state.forms.issue.content' },
{ pattern: /\bnewIssueLabels\b/g, replacement: 'state.forms.issue.labels' },
{ pattern: /\bnewPRSubject\b/g, replacement: 'state.forms.pr.subject' },
{ pattern: /\bnewPRContent\b/g, replacement: 'state.forms.pr.content' },
{ pattern: /\bnewPRCommitId\b/g, replacement: 'state.forms.pr.commitId' },
{ pattern: /\bnewPRBranchName\b/g, replacement: 'state.forms.pr.branchName' },
{ pattern: /\bnewPRLabels\b/g, replacement: 'state.forms.pr.labels' },
{ pattern: /\bnewPatchContent\b/g, replacement: 'state.forms.patch.content' },
{ pattern: /\bnewPatchSubject\b/g, replacement: 'state.forms.patch.subject' },
{ pattern: /\bnewReleaseTagName\b/g, replacement: 'state.forms.release.tagName' },
{ pattern: /\bnewReleaseTagHash\b/g, replacement: 'state.forms.release.tagHash' },
{ pattern: /\bnewReleaseNotes\b/g, replacement: 'state.forms.release.notes' },
{ pattern: /\bnewReleaseIsDraft\b/g, replacement: 'state.forms.release.isDraft' },
{ pattern: /\bnewReleaseIsPrerelease\b/g, replacement: 'state.forms.release.isPrerelease' },
{ pattern: /\bnewThreadTitle\b/g, replacement: 'state.forms.discussion.threadTitle' },
{ pattern: /\bnewThreadContent\b/g, replacement: 'state.forms.discussion.threadContent' },
{ pattern: /\breplyContent\b/g, replacement: 'state.forms.discussion.replyContent' },
{ pattern: /\bselectedPatchText\b/g, replacement: 'state.forms.patchHighlight.text' },
{ pattern: /\bselectedPatchStartLine\b/g, replacement: 'state.forms.patchHighlight.startLine' },
{ pattern: /\bselectedPatchEndLine\b/g, replacement: 'state.forms.patchHighlight.endLine' },
{ pattern: /\bselectedPatchStartPos\b/g, replacement: 'state.forms.patchHighlight.startPos' },
{ pattern: /\bselectedPatchEndPos\b/g, replacement: 'state.forms.patchHighlight.endPos' },
{ pattern: /\bpatchHighlightComment\b/g, replacement: 'state.forms.patchHighlight.comment' },
{ pattern: /\bpatchCommentContent\b/g, replacement: 'state.forms.patchComment.content' },
{ pattern: /\breplyingToPatchComment\b/g, replacement: 'state.forms.patchComment.replyingTo' },
// Dialogs
{ pattern: /\bshowCreateFileDialog\b/g, replacement: "state.openDialog === 'createFile'" },
{ pattern: /\bshowCreateBranchDialog\b/g, replacement: "state.openDialog === 'createBranch'" },
{ pattern: /\bshowCreateTagDialog\b/g, replacement: "state.openDialog === 'createTag'" },
{ pattern: /\bshowCommitDialog\b/g, replacement: "state.openDialog === 'commit'" },
{ pattern: /\bshowCreateIssueDialog\b/g, replacement: "state.openDialog === 'createIssue'" },
{ pattern: /\bshowCreatePRDialog\b/g, replacement: "state.openDialog === 'createPR'" },
{ pattern: /\bshowCreatePatchDialog\b/g, replacement: "state.openDialog === 'createPatch'" },
{ pattern: /\bshowCreateReleaseDialog\b/g, replacement: "state.openDialog === 'createRelease'" },
{ pattern: /\bshowCreateThreadDialog\b/g, replacement: "state.openDialog === 'createThread'" },
{ pattern: /\bshowReplyDialog\b/g, replacement: "state.openDialog === 'reply'" },
{ pattern: /\bshowVerificationDialog\b/g, replacement: "state.openDialog === 'verification'" },
{ pattern: /\bshowCloneUrlVerificationDialog\b/g, replacement: "state.openDialog === 'cloneUrlVerification'" },
{ pattern: /\bshowPatchHighlightDialog\b/g, replacement: "state.openDialog === 'patchHighlight'" },
{ pattern: /\bshowPatchCommentDialog\b/g, replacement: "state.openDialog === 'patchComment'" },
// Selected items
{ pattern: /\bselectedIssue\b/g, replacement: 'state.selected.issue' },
{ pattern: /\bselectedPR\b/g, replacement: 'state.selected.pr' },
{ pattern: /\bselectedPatch\b/g, replacement: 'state.selected.patch' },
{ pattern: /\bselectedDiscussion\b/g, replacement: 'state.selected.discussion' },
// Creating flags
{ pattern: /\bcreatingPatch\b/g, replacement: 'state.creating.patch' },
{ pattern: /\bcreatingThread\b/g, replacement: 'state.creating.thread' },
{ pattern: /\bcreatingReply\b/g, replacement: 'state.creating.reply' },
{ pattern: /\bcreatingRelease\b/g, replacement: 'state.creating.release' },
{ pattern: /\bcreatingPatchHighlight\b/g, replacement: 'state.creating.patchHighlight' },
{ pattern: /\bcreatingPatchComment\b/g, replacement: 'state.creating.patchComment' },
{ pattern: /\bdeletingAnnouncement\b/g, replacement: 'state.creating.announcement' },
// Maintainers
{ pattern: /\bisMaintainer\b/g, replacement: 'state.maintainers.isMaintainer' },
{ pattern: /\ballMaintainers\b/g, replacement: 'state.maintainers.all' },
{ pattern: /\bmaintainersLoaded\b/g, replacement: 'state.maintainers.loaded' },
{ pattern: /\bmaintainersEffectRan\b/g, replacement: 'state.maintainers.effectRan' },
{ pattern: /\blastRepoKey\b/g, replacement: 'state.maintainers.lastRepoKey' },
// Clone
{ pattern: /\bisRepoCloned\b/g, replacement: 'state.clone.isCloned' },
{ pattern: /\bcheckingCloneStatus\b/g, replacement: 'state.clone.checking' },
{ pattern: /\bcloning\b/g, replacement: 'state.clone.cloning' },
{ pattern: /\bcopyingCloneUrl\b/g, replacement: 'state.clone.copyingUrl' },
{ pattern: /\bapiFallbackAvailable\b/g, replacement: 'state.clone.apiFallbackAvailable' },
{ pattern: /\bcloneUrlsExpanded\b/g, replacement: 'state.clone.urlsExpanded' },
{ pattern: /\bshowAllCloneUrls\b/g, replacement: 'state.clone.showAllUrls' },
{ pattern: /\bcloneUrlReachability\b/g, replacement: 'state.clone.reachability' },
{ pattern: /\bcheckingReachability\b/g, replacement: 'state.clone.checkingReachability' },
// Verification
{ pattern: /\bverificationStatus\b/g, replacement: 'state.verification.status' },
{ pattern: /\bverificationFileContent\b/g, replacement: 'state.verification.fileContent' },
{ pattern: /\bverifyingCloneUrl\b/g, replacement: 'state.verification.selectedCloneUrl' },
{ pattern: /\bselectedCloneUrlForVerification\b/g, replacement: 'state.verification.selectedCloneUrl' },
// Docs
{ pattern: /\bdocumentationContent\b/g, replacement: 'state.docs.content' },
{ pattern: /\bdocumentationHtml\b/g, replacement: 'state.docs.html' },
{ pattern: /\bdocumentationKind\b/g, replacement: 'state.docs.kind' },
// Code search
{ pattern: /\bcodeSearchQuery\b/g, replacement: 'state.codeSearch.query' },
{ pattern: /\bcodeSearchResults\b/g, replacement: 'state.codeSearch.results' },
{ pattern: /\bcodeSearchScope\b/g, replacement: 'state.codeSearch.scope' },
// Fork/Bookmark
{ pattern: /\bforkInfo\b/g, replacement: 'state.fork.info' },
{ pattern: /\bforking\b/g, replacement: 'state.fork.forking' },
{ pattern: /\bisBookmarked\b/g, replacement: 'state.bookmark.isBookmarked' },
// Metadata
{ pattern: /\brepoAddress\b/g, replacement: 'state.metadata.address' },
{ pattern: /\brepoImage\b/g, replacement: 'state.metadata.image' },
{ pattern: /\brepoBanner\b/g, replacement: 'state.metadata.banner' },
{ pattern: /\brepoOwnerPubkeyState\b/g, replacement: 'state.metadata.ownerPubkey' },
{ pattern: /\breadmeAutoLoadAttempted\b/g, replacement: 'state.metadata.readmeAutoLoadAttempted' },
// Discussion
{ pattern: /\breplyingToThread\b/g, replacement: 'state.discussion.replyingToThread' },
{ pattern: /\breplyingToComment\b/g, replacement: 'state.discussion.replyingToComment' },
{ pattern: /\bdiscussionEvents\b/g, replacement: 'state.discussion.events' },
{ pattern: /\bnostrLinkEvents\b/g, replacement: 'state.discussion.nostrLinkEvents' },
{ pattern: /\bnostrLinkProfiles\b/g, replacement: 'state.discussion.nostrLinkProfiles' },
// Other
{ pattern: /\bpatchEditor\b/g, replacement: 'state.patchEditor' },
{ pattern: /\bsaving\b/g, replacement: 'state.saving' },
{ pattern: /\bisMounted\b/g, replacement: 'state.isMounted' },
{ pattern: /\brepoNotFound\b/g, replacement: 'state.repoNotFound' },
{ pattern: /\berror\b/g, replacement: 'state.error' },
// Status updates
{ pattern: /\bupdatingIssueStatus\b/g, replacement: 'state.statusUpdates.issue' },
{ pattern: /\bupdatingPatchStatus\b/g, replacement: 'state.statusUpdates.patch' },
// Data collections (keep as-is but ensure they're accessed via state)
{ pattern: /\bissues\b/g, replacement: 'state.issues' },
{ pattern: /\bissueReplies\b/g, replacement: 'state.issueReplies' },
{ pattern: /\bprs\b/g, replacement: 'state.prs' },
{ pattern: /\bpatches\b/g, replacement: 'state.patches' },
{ pattern: /\bpatchHighlights\b/g, replacement: 'state.patchHighlights' },
{ pattern: /\bpatchComments\b/g, replacement: 'state.patchComments' },
{ pattern: /\bdiscussions\b/g, replacement: 'state.discussions' },
{ pattern: /\breleases\b/g, replacement: 'state.releases' },
];
// Special cases that need context-aware replacement
const contextAwareReplacements = [
// Dialog assignments
{
pattern: /(showCreateFileDialog|showCreateBranchDialog|showCreateTagDialog|showCommitDialog|showCreateIssueDialog|showCreatePRDialog|showCreatePatchDialog|showCreateReleaseDialog|showCreateThreadDialog|showReplyDialog|showVerificationDialog|showCloneUrlVerificationDialog|showPatchHighlightDialog|showPatchCommentDialog)\s*=\s*(true|false)/g,
replacement: (match, varName, value) => {
const dialogMap = {
showCreateFileDialog: 'createFile',
showCreateBranchDialog: 'createBranch',
showCreateTagDialog: 'createTag',
showCommitDialog: 'commit',
showCreateIssueDialog: 'createIssue',
showCreatePRDialog: 'createPR',
showCreatePatchDialog: 'createPatch',
showCreateReleaseDialog: 'createRelease',
showCreateThreadDialog: 'createThread',
showReplyDialog: 'reply',
showVerificationDialog: 'verification',
showCloneUrlVerificationDialog: 'cloneUrlVerification',
showPatchHighlightDialog: 'patchHighlight',
showPatchCommentDialog: 'patchComment'
};
const dialogType = dialogMap[varName];
return value === 'true' ? `state.openDialog = '${dialogType}'` : `state.openDialog = null`;
}
}
];
function migrateFile(content) {
let migrated = content;
// Apply simple replacements
for (const { pattern, replacement } of migrations) {
migrated = migrated.replace(pattern, replacement);
}
// Apply context-aware replacements
for (const { pattern, replacement } of contextAwareReplacements) {
if (typeof replacement === 'function') {
migrated = migrated.replace(pattern, replacement);
} else {
migrated = migrated.replace(pattern, replacement);
}
}
return migrated;
}
// Read file
console.log(`Reading ${targetFile}...`);
let content = readFileSync(targetFile, 'utf-8');
// Backup original
const backupFile = targetFile + '.backup';
writeFileSync(backupFile, content, 'utf-8');
console.log(`Backup created: ${backupFile}`);
// Migrate
console.log('Applying migrations...');
const migrated = migrateFile(content);
// Write migrated file
writeFileSync(targetFile, migrated, 'utf-8');
console.log(`Migration complete!`);
console.log(`\n Please review the changes carefully.`);
console.log(` Some replacements may need manual adjustment.`);
console.log(` Backup saved to: ${backupFile}`);