-
Notifications
You must be signed in to change notification settings - Fork 9
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #353 from Vandivier/338-init-custom-instructions
338 init custom instructions
- Loading branch information
Showing
42 changed files
with
16,002 additions
and
4 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -43,4 +43,7 @@ yarn-error.log* | |
*.tsbuildinfo | ||
|
||
# idea files | ||
.idea | ||
.idea | ||
|
||
# python | ||
.venv |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,101 @@ | ||
const fs = require('fs-extra') | ||
const path = require('path') | ||
|
||
require('dotenv').config({ path: path.resolve(__dirname, '../.env.local') }) | ||
|
||
const { PrismaClient } = require('@prisma/client') | ||
|
||
const prisma = new PrismaClient() | ||
|
||
const backup = async () => { | ||
const checklistNames = await prisma.checklist.groupBy({ | ||
by: ['name'], | ||
}) | ||
|
||
let checklists = [] | ||
|
||
for (const { name } of checklistNames) { | ||
const checklist = await prisma.checklist.findFirst({ | ||
where: { name }, | ||
orderBy: { createdAt: 'desc' }, | ||
include: { | ||
checklistItems: { | ||
orderBy: { | ||
displayIndex: 'asc', | ||
}, | ||
}, | ||
}, | ||
}) | ||
checklists.push(checklist) | ||
} | ||
|
||
const existingChecklistsRaw = fs.readFileSync( | ||
path.resolve(__dirname, '../db/checklists.json') | ||
) | ||
let existingChecklists = JSON.parse(existingChecklistsRaw.toString()) | ||
const existingChecklistNames = existingChecklists.map( | ||
(checklist) => checklist.name | ||
) | ||
|
||
const premiumChecklistsPath = path.resolve( | ||
__dirname, | ||
'../db/premium-checklists.json' | ||
) | ||
let premiumChecklists = [] | ||
|
||
if (fs.existsSync(premiumChecklistsPath)) { | ||
const premiumChecklistsRaw = fs.readFileSync(premiumChecklistsPath) | ||
premiumChecklists = JSON.parse(premiumChecklistsRaw.toString()) | ||
} | ||
|
||
for (const checklist of checklists) { | ||
const { name, version, checklistItems } = checklist | ||
const items = checklistItems.map((item) => { | ||
if ( | ||
item.linkText === '' && | ||
item.linkUri === '' && | ||
item.isRequired === true && | ||
item.detailText === '' | ||
) { | ||
return item.displayText | ||
} else { | ||
return { | ||
detailText: item.detailText, | ||
displayText: item.displayText, | ||
isRequired: item.isRequired, | ||
linkText: item.linkText, | ||
linkUri: item.linkUri, | ||
} | ||
} | ||
}) | ||
|
||
const checklistData = { name, version, items } | ||
|
||
if (existingChecklistNames.includes(name)) { | ||
existingChecklists = existingChecklists.map((checklist) => | ||
checklist.name === name ? checklistData : checklist | ||
) | ||
} else { | ||
premiumChecklists.push(checklistData) | ||
} | ||
} | ||
|
||
fs.writeFileSync( | ||
path.resolve(__dirname, '../db/checklists.json'), | ||
JSON.stringify(existingChecklists, null, 2) | ||
) | ||
fs.writeFileSync( | ||
premiumChecklistsPath, | ||
JSON.stringify(premiumChecklists, null, 2) | ||
) | ||
|
||
console.log('Checklist backup completed!') | ||
} | ||
|
||
backup() | ||
.catch((e) => { | ||
throw e | ||
}) | ||
.finally(async () => { | ||
await prisma.$disconnect() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
const fs = require('fs-extra') | ||
const path = require('path') | ||
|
||
require('dotenv').config({ path: path.resolve(__dirname, '../.env.local') }) | ||
|
||
const { PrismaClient } = require('@prisma/client') | ||
|
||
const prisma = new PrismaClient() | ||
|
||
async function backupUsers() { | ||
const users = await prisma.user.findMany() | ||
const jsonUsers = JSON.stringify(users, null, 2) | ||
const date = new Date() | ||
const isoDate = date.toISOString().replace(/:/g, '-') | ||
const fileName = `./db/bak.users.${isoDate}.json` | ||
await fs.writeFile(fileName, jsonUsers) | ||
console.log(`Backup of ${users.length} users completed!`) | ||
} | ||
|
||
backupUsers() | ||
.catch((e) => { | ||
throw e | ||
}) | ||
.finally(async () => { | ||
await prisma.$disconnect() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import path from 'path' | ||
|
||
require('dotenv').config({ path: path.resolve(__dirname, '../.env.local') }) | ||
|
||
import db from '../db' | ||
|
||
async function deleteChecklist(checklistId: number) { | ||
const checklist = await db.checklist.findUnique({ | ||
where: { id: checklistId }, | ||
}) | ||
|
||
if (!checklist) { | ||
throw new Error(`Checklist with ID ${checklistId} not found.`) | ||
} | ||
|
||
// Cascade delete userChecklistItems related to this checklist | ||
await db.userChecklistItem.deleteMany({ | ||
where: { | ||
userChecklist: { | ||
checklistId: checklistId, | ||
}, | ||
}, | ||
}) | ||
|
||
// Cascade delete userChecklists related to this checklist | ||
await db.userChecklist.deleteMany({ | ||
where: { checklistId }, | ||
}) | ||
|
||
// Cascade delete checklistItems related to this checklist | ||
await db.checklistItem.deleteMany({ | ||
where: { checklistId }, | ||
}) | ||
|
||
// Finally, delete the checklist itself | ||
await db.checklist.delete({ | ||
where: { id: checklistId }, | ||
}) | ||
|
||
console.log( | ||
`Checklist with ID ${checklistId} and all related entities have been deleted.` | ||
) | ||
} | ||
|
||
// Main script execution | ||
const main = async () => { | ||
const checklistIdAsStr = | ||
process.argv | ||
.find((arg) => arg.startsWith('--checklistId=')) | ||
?.split('=')[1] || '' | ||
const checklistId = parseInt(checklistIdAsStr, 10) | ||
|
||
if (!checklistId) { | ||
console.log( | ||
'Did not receive a valid checklistId. \n' + | ||
'Received: ' + | ||
checklistIdAsStr + | ||
'\n' + | ||
'From the scripts/ dir, call this script like:\n' + | ||
'`npx ts-node -P tsconfig.script.json scripts/cascadeDeleteChecklist.ts --checklistId=123`\n' + | ||
'Exiting.' | ||
) | ||
process.exit(1) | ||
} | ||
|
||
try { | ||
await deleteChecklist(checklistId) | ||
process.exit(0) | ||
} catch (error) { | ||
console.error('An error occurred:', error) | ||
process.exit(1) | ||
} | ||
} | ||
|
||
main() | ||
.catch((e) => { | ||
throw e | ||
}) | ||
.finally(async () => { | ||
await db.$disconnect() | ||
}) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,123 @@ | ||
// run this from the root dir, `ladderly-3/` | ||
// optionally pass the autofix flag, like so: | ||
// `node scripts/ci/custom-blog-lint.js --autofix` | ||
|
||
const fs = require('fs') | ||
const path = require('path') | ||
const matter = require('gray-matter') | ||
|
||
const BLOG_DIR = path.join(process.cwd(), 'src', 'app', 'blog') | ||
const VOTABLES_PATH = path.join( | ||
process.cwd(), | ||
'db', | ||
'seed-utils', | ||
'votables.json' | ||
) | ||
|
||
/** | ||
* @typedef {Object} BlogInfo | ||
* @property {string} filename | ||
* @property {string} title | ||
*/ | ||
|
||
/** | ||
* @typedef {Object} Votable | ||
* @property {string} type | ||
* @property {string} name | ||
* @property {string} website | ||
* @property {string[]} tags | ||
*/ | ||
|
||
/** | ||
* @returns {BlogInfo[]} | ||
*/ | ||
function getBlogInfo() { | ||
return fs | ||
.readdirSync(BLOG_DIR) | ||
.filter((file) => file.endsWith('.md')) | ||
.map((file) => { | ||
const content = fs.readFileSync(path.join(BLOG_DIR, file), 'utf-8') | ||
const { data } = matter(content) | ||
return { | ||
filename: file.replace('.md', ''), | ||
title: data.title || '', | ||
} | ||
}) | ||
} | ||
|
||
/** | ||
* @returns {Votable[]} | ||
*/ | ||
function getVotables() { | ||
const votablesContent = fs.readFileSync(VOTABLES_PATH, 'utf-8') | ||
return JSON.parse(votablesContent) | ||
} | ||
|
||
/** | ||
* @param {Votable[]} votables | ||
*/ | ||
function saveVotables(votables) { | ||
fs.writeFileSync(VOTABLES_PATH, JSON.stringify(votables, null, 2)) | ||
} | ||
|
||
/** | ||
* @param {boolean} autofix | ||
*/ | ||
function checkBlogArticlesInVotables(autofix) { | ||
const blogInfo = getBlogInfo() | ||
const votables = getVotables() | ||
|
||
/** @type {BlogInfo[]} */ | ||
const missingArticles = [] | ||
|
||
for (const info of blogInfo) { | ||
const isInVotables = votables.some( | ||
(votable) => | ||
votable.type === 'CONTENT' && | ||
votable.website === `https://www.ladderly.io/blog/${info.filename}` | ||
) | ||
|
||
if (!isInVotables) { | ||
missingArticles.push(info) | ||
} | ||
} | ||
|
||
if (missingArticles.length > 0) { | ||
console.error('The following blog articles are missing from votables.json:') | ||
missingArticles.forEach((article) => { | ||
console.error(`- ${article.filename}`) | ||
const newVotable = { | ||
type: 'CONTENT', | ||
name: article.title, | ||
website: `https://www.ladderly.io/blog/${article.filename}`, | ||
tags: ['Ladderly.io Article'], | ||
} | ||
|
||
if (autofix) { | ||
votables.push(newVotable) | ||
console.log(`Added ${article.filename} to votables.json`) | ||
} else { | ||
console.error('Suggested JSON snippet to add:') | ||
console.error(JSON.stringify(newVotable, null, 2)) | ||
console.error('\n') | ||
} | ||
}) | ||
|
||
if (autofix) { | ||
saveVotables(votables) | ||
console.log('votables.json has been updated.') | ||
} else { | ||
console.error( | ||
'Run with --autofix to automatically add missing articles to votables.json' | ||
) | ||
process.exit(1) // Exit with an error code | ||
} | ||
} else { | ||
console.log('All blog articles are included in votables.json') | ||
} | ||
} | ||
|
||
// Check if --autofix flag is provided | ||
const autofix = process.argv.includes('--autofix') | ||
|
||
checkBlogArticlesInVotables(autofix) |
Oops, something went wrong.