diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md index 469bd1e..2a8c599 100644 --- a/.github/CONTRIBUTING.md +++ b/.github/CONTRIBUTING.md @@ -49,6 +49,8 @@ Please follow the commit specification. See [`.commitlintrc.json`](https://githu ### Commonly used NPM scripts ```bash +# add new problem +$ yarn new # run project in development mode $ yarn dev # build all dist files diff --git a/config/problems.json b/config/problems.json index 26a0acf..f09a261 100644 --- a/config/problems.json +++ b/config/problems.json @@ -3,19 +3,22 @@ "key": "HelloWorld", "subject": "Basic Tutorial", "subjectKey": "BasicTutorial", - "title": "Hello, world!" + "title": "Hello, world!", + "author": "ZLY201" }, { "key": "EverydayTypes", "subject": "Basic Tutorial", "subjectKey": "BasicTutorial", - "title": "EveryDay Types" + "title": "EveryDay Types", + "author": "ZLY201" }, { "key": "TransposeMatrix", "subject": "Difficulties", "subjectKey": "Difficulties", "title": "Transpose Matrix", + "author": "ZLY201", "cases": [ { "source": "[[1, 2]]", diff --git a/package.json b/package.json index 0a9d662..9e0c6e6 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "dev": "yarn build:ssr && rspack serve --watch", "build:ssr": "yarn clean && rspack build --config=rspack.ssr.config.ts", "build": "yarn build:ssr && rspack build && rm -rf dist/ssr", + "new": "ts-node tools/addNewProblem.ts", "lint": "eslint --fix --color --cache --quiet .", "prepare": "husky install" }, @@ -58,6 +59,7 @@ "@types/event-emitter": "^0.3.4", "@types/lodash.debounce": "^4.0.7", "@types/node": "^20.8.9", + "@types/prompts": "^2.4.9", "@types/react": "^17.0.67", "@types/react-copy-to-clipboard": "^5.0.6", "@types/react-dom": "^17.0.21", @@ -82,6 +84,7 @@ "lint-staged": "^14.0.1", "monaco-editor": "^0.44.0", "prettier": "^3.0.3", + "prompts": "^2.4.2", "style-loader": "^3.3.3", "ts-node": "^10.9.1", "typescript": "^5.2.2" diff --git a/src/modules/Question/Description.tsx b/src/modules/Question/Description.tsx index 5265f4c..37ac3eb 100644 --- a/src/modules/Question/Description.tsx +++ b/src/modules/Question/Description.tsx @@ -3,7 +3,6 @@ import { Skeleton } from '@arco-design/web-react'; import debounce from 'lodash.debounce'; import Markdown from '@src/components/Markdown'; import Context from '@src/utils/context'; -import linkJson from '@config/links.json'; import { getProblemDocs, NULL_CASE, @@ -24,15 +23,7 @@ const Description = function () { setting: { theme, language }, }, ] = useContext(Context); - const { - key, - title, - contributor: { name, link } = { - name: 'ZLY201', - link: linkJson['github-zly201'], - }, - cases = [NULL_CASE], - } = currentProblem; + const { key, title, author, cases = [NULL_CASE] } = currentProblem; const [desc, setDesc] = useState(''); const [state, setState] = useState(false); const [loading, setLoading] = useState(true); @@ -107,16 +98,18 @@ const Description = function () { -
+ {author && ( + + )} ); }; diff --git a/src/utils/problems.ts b/src/utils/problems.ts index 835d3c2..7f2bb46 100644 --- a/src/utils/problems.ts +++ b/src/utils/problems.ts @@ -12,10 +12,7 @@ export type Problem = { subject: string; subjectKey: string; title: string; - contributor?: { - name: string; - link: string; - }; + author?: string; keywords?: string[]; cases?: { source: string; diff --git a/tools/addNewProblem.ts b/tools/addNewProblem.ts new file mode 100644 index 0000000..1768f2f --- /dev/null +++ b/tools/addNewProblem.ts @@ -0,0 +1,117 @@ +import fs from 'fs'; +import path from 'path'; +import prompts from 'prompts'; +import chalk from 'chalk'; +import problemJson from '../config/problems.json'; + +const PROBLEMS_PATH = path.resolve(__dirname, '../problems'); +const NEW_TYPE_TAG = 'new problem type'; +const HELLO_WORLD_PATH = path.resolve( + PROBLEMS_PATH, + 'basic-tutorial/1-hello-world', +); +const PROBLEM_JSON_PATH = path.resolve(__dirname, '../config/problems.json'); + +function handleStringWithDivider(source: string, divider: string = '') { + return source + .split('-') + .map(str => `${str[0].toUpperCase()}${str.slice(1)}`) + .join(divider); +} + +async function main() { + const types: string[] = []; + const typeFiles = fs.readdirSync(PROBLEMS_PATH); + typeFiles.forEach(function (item) { + const stat = fs.lstatSync(path.resolve(PROBLEMS_PATH, item)); + if (stat.isDirectory() === true) { + types.push(item); + } + }); + const typesChoices: prompts.Choice[] = types.map(type => ({ + title: type, + value: type, + })); + typesChoices.push({ + title: NEW_TYPE_TAG, + value: NEW_TYPE_TAG, + description: 'Add a new problem type', + }); + let { problemType } = await prompts({ + type: 'select', + name: 'problemType', + message: 'What type of problem do you want to create?', + choices: typesChoices, + }); + if (problemType === NEW_TYPE_TAG) { + const { newTypeName } = await prompts({ + type: 'text', + name: 'newTypeName', + initial: 'template-type', + message: 'What is the name of the new type?', + validate: value => + value === NEW_TYPE_TAG || types.includes(value) + ? 'This type already exists!' + : Boolean(value), + }); + fs.mkdirSync(path.resolve(PROBLEMS_PATH, newTypeName)); + problemType = newTypeName; + } + const problemDirPath = path.resolve(PROBLEMS_PATH, problemType); + const problemsFiles = fs.readdirSync(problemDirPath); + const problemNumber = + problemsFiles.filter(function (item) { + const stat = fs.lstatSync(path.resolve(problemDirPath, item)); + return stat.isDirectory(); + }).length + 1; + const { newProblemName } = await prompts({ + type: 'text', + name: 'newProblemName', + message: 'What is the name of the new problem?', + initial: 'template-problem', + validate: value => + value === NEW_TYPE_TAG || + problemsFiles.includes(`${problemNumber}-${value}`) + ? 'This problem already exists!' + : Boolean(value), + }); + const { githubName } = await prompts({ + type: 'text', + name: 'githubName', + message: 'Your github name to thanks:', + }); + const newProblemPath = path.resolve( + problemDirPath, + `${problemNumber}-${newProblemName}`, + ); + fs.cpSync(HELLO_WORLD_PATH, newProblemPath, { recursive: true }); + problemJson.push({ + key: handleStringWithDivider(newProblemName), + subject: handleStringWithDivider(problemType, ' '), + subjectKey: handleStringWithDivider(problemType), + title: handleStringWithDivider(newProblemName, ' '), + author: githubName, + cases: [], + }); + fs.writeFileSync( + PROBLEM_JSON_PATH, + JSON.stringify(problemJson, undefined, 2), + { + encoding: 'utf-8', + }, + ); + console.log( + `The new problem ${chalk.underline.green( + `${problemType}:${newProblemName}`, + )} has been created at ${chalk.underline.blue( + `problems/${problemNumber}-${newProblemName}`, + )}.`, + ); + console.log( + `Please go ${chalk.blue.underline( + 'config/problems.json', + )} to edit the config of this new problem.`, + ); +} + +main(); diff --git a/yarn.lock b/yarn.lock index 6f16611..f5e3947 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1941,6 +1941,14 @@ resolved "https://registry.yarnpkg.com/@types/normalize-package-data/-/normalize-package-data-2.4.4.tgz#56e2cc26c397c038fab0e3a917a12d5c5909e901" integrity sha512-37i+OaWTh9qeK4LSHPsyRC7NahnGotNuZvjLSgcPzblpHB3rrCJxAOgI5gCdKm7coonsaX1Of0ILiTcnZjbfxA== +"@types/prompts@^2.4.9": + version "2.4.9" + resolved "https://registry.yarnpkg.com/@types/prompts/-/prompts-2.4.9.tgz#8775a31e40ad227af511aa0d7f19a044ccbd371e" + integrity sha512-qTxFi6Buiu8+50/+3DGIWLHM6QuWsEKugJnnP6iv2Mc4ncxE4A/OJkjuVOA+5X0X1S/nq5VJRa8Lu+nwcvbrKA== + dependencies: + "@types/node" "*" + kleur "^3.0.3" + "@types/prop-types@*": version "15.7.10" resolved "https://registry.yarnpkg.com/@types/prop-types/-/prop-types-15.7.10.tgz#892afc9332c4d62a5ea7e897fe48ed2085bbb08a" @@ -5209,6 +5217,11 @@ kind-of@^6.0.3: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== +kleur@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/kleur/-/kleur-3.0.3.tgz#a79c9ecc86ee1ce3fa6206d1216c501f147fc07e" + integrity sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w== + kleur@^4.0.3: version "4.1.5" resolved "https://registry.yarnpkg.com/kleur/-/kleur-4.1.5.tgz#95106101795f7050c6c650f350c683febddb1780" @@ -6657,6 +6670,14 @@ process-nextick-args@~2.0.0: resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2" integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag== +prompts@^2.4.2: + version "2.4.2" + resolved "https://registry.yarnpkg.com/prompts/-/prompts-2.4.2.tgz#7b57e73b3a48029ad10ebd44f74b01722a4cb069" + integrity sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q== + dependencies: + kleur "^3.0.3" + sisteransi "^1.0.5" + prop-types@^15.0.0, prop-types@^15.6.2, prop-types@^15.8.1: version "15.8.1" resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.8.1.tgz#67d87bf1a694f48435cf332c24af10214a3140b5" @@ -7373,6 +7394,11 @@ sirv@^1.0.7: mrmime "^1.0.0" totalist "^1.0.0" +sisteransi@^1.0.5: + version "1.0.5" + resolved "https://registry.yarnpkg.com/sisteransi/-/sisteransi-1.0.5.tgz#134d681297756437cc05ca01370d3a7a571075ed" + integrity sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634"