diff --git a/config/links.json b/config/links.json index d26fe5a..7ff1c4a 100644 --- a/config/links.json +++ b/config/links.json @@ -1,4 +1,3 @@ { - "github-repo": "https://github.com/typescript-tutorial-exercises/core", - "github-zly201": "https://github.com/zly201" + "github-repo": "https://github.com/typescript-tutorial-exercises" } diff --git a/problems/basic-tutorial/1-hello-world/docs/description/description.en.md b/problems/basic-tutorial/1-hello-world/docs/description/description.en.md index 3719a71..a3416c4 100644 --- a/problems/basic-tutorial/1-hello-world/docs/description/description.en.md +++ b/problems/basic-tutorial/1-hello-world/docs/description/description.en.md @@ -24,9 +24,9 @@ Now, you can go to the editor at right of the page to start your TypeScript trav **Reference** -> 1.https://www.typescriptlang.org/ -> -> 2.https://www.w3schools.com/typescript/typescript_intro.php -> -> 3.https://github.com/typescript-exercises/typescript-exercises +> 1.[https://www.typescriptlang.org/](https://www.typescriptlang.org/) +> +> 2.[https://www.w3schools.com/typescript/typescript_intro.php](https://www.w3schools.com/typescript/typescript_intro.php) +> +> 3.[https://github.com/typescript-exercises/typescript-exercises](https://github.com/typescript-exercises/typescript-exercises) diff --git a/problems/basic-tutorial/1-hello-world/docs/description/description.zh-cn.md b/problems/basic-tutorial/1-hello-world/docs/description/description.zh-cn.md index db02dee..e46ac87 100644 --- a/problems/basic-tutorial/1-hello-world/docs/description/description.zh-cn.md +++ b/problems/basic-tutorial/1-hello-world/docs/description/description.zh-cn.md @@ -24,8 +24,8 @@ TypeScript 允许指定代码中传递的数据类型,并且能够在类型不 **参考** -> 1.https://www.typescriptlang.org/ +> 1.[https://www.typescriptlang.org/](https://www.typescriptlang.org/) > -> 2.https://www.w3schools.com/typescript/typescript_intro.php +> 2.[https://www.w3schools.com/typescript/typescript_intro.php](https://www.w3schools.com/typescript/typescript_intro.php) > -> 3.https://github.com/typescript-exercises/typescript-exercises +> 3.[https://github.com/typescript-exercises/typescript-exercises](https://github.com/typescript-exercises/typescript-exercises) diff --git a/problems/basic-tutorial/2-everyday-types/docs/description/description.en.md b/problems/basic-tutorial/2-everyday-types/docs/description/description.en.md index b96a1fd..7af2212 100644 --- a/problems/basic-tutorial/2-everyday-types/docs/description/description.en.md +++ b/problems/basic-tutorial/2-everyday-types/docs/description/description.en.md @@ -2,4 +2,4 @@ Please replace all unknown and any in the code on the right with the correct typ **Reference** -> https://www.typescriptlang.org/docs/handbook/2/everyday-types.html +> [https://www.typescriptlang.org/docs/handbook/2/everyday-types.html](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) diff --git a/problems/basic-tutorial/2-everyday-types/docs/description/description.zh-cn.md b/problems/basic-tutorial/2-everyday-types/docs/description/description.zh-cn.md index 43d9d3a..7f47ec2 100644 --- a/problems/basic-tutorial/2-everyday-types/docs/description/description.zh-cn.md +++ b/problems/basic-tutorial/2-everyday-types/docs/description/description.zh-cn.md @@ -2,4 +2,4 @@ **参考** -> https://www.typescriptlang.org/docs/handbook/2/everyday-types.html +> [https://www.typescriptlang.org/docs/handbook/2/everyday-types.html](https://www.typescriptlang.org/docs/handbook/2/everyday-types.html) diff --git a/problems/difficulties/transpose-matrix/check.ts b/problems/difficulties/1-transpose-matrix/check.ts similarity index 100% rename from problems/difficulties/transpose-matrix/check.ts rename to problems/difficulties/1-transpose-matrix/check.ts diff --git a/problems/difficulties/transpose-matrix/docs/description/description.en.md b/problems/difficulties/1-transpose-matrix/docs/description/description.en.md similarity index 100% rename from problems/difficulties/transpose-matrix/docs/description/description.en.md rename to problems/difficulties/1-transpose-matrix/docs/description/description.en.md diff --git a/problems/difficulties/transpose-matrix/docs/description/description.zh-cn.md b/problems/difficulties/1-transpose-matrix/docs/description/description.zh-cn.md similarity index 100% rename from problems/difficulties/transpose-matrix/docs/description/description.zh-cn.md rename to problems/difficulties/1-transpose-matrix/docs/description/description.zh-cn.md diff --git a/problems/difficulties/transpose-matrix/docs/description/index.ts b/problems/difficulties/1-transpose-matrix/docs/description/index.ts similarity index 100% rename from problems/difficulties/transpose-matrix/docs/description/index.ts rename to problems/difficulties/1-transpose-matrix/docs/description/index.ts diff --git a/problems/difficulties/transpose-matrix/docs/tutorial/index.ts b/problems/difficulties/1-transpose-matrix/docs/tutorial/index.ts similarity index 100% rename from problems/difficulties/transpose-matrix/docs/tutorial/index.ts rename to problems/difficulties/1-transpose-matrix/docs/tutorial/index.ts diff --git a/problems/difficulties/transpose-matrix/docs/tutorial/tutorial.en.md b/problems/difficulties/1-transpose-matrix/docs/tutorial/tutorial.en.md similarity index 100% rename from problems/difficulties/transpose-matrix/docs/tutorial/tutorial.en.md rename to problems/difficulties/1-transpose-matrix/docs/tutorial/tutorial.en.md diff --git a/problems/difficulties/transpose-matrix/index.ts b/problems/difficulties/1-transpose-matrix/index.ts similarity index 100% rename from problems/difficulties/transpose-matrix/index.ts rename to problems/difficulties/1-transpose-matrix/index.ts diff --git a/problems/difficulties/transpose-matrix/template.ts b/problems/difficulties/1-transpose-matrix/template.ts similarity index 100% rename from problems/difficulties/transpose-matrix/template.ts rename to problems/difficulties/1-transpose-matrix/template.ts diff --git a/problems/difficulties/transpose-matrix/test b/problems/difficulties/1-transpose-matrix/test similarity index 100% rename from problems/difficulties/transpose-matrix/test rename to problems/difficulties/1-transpose-matrix/test diff --git a/problems/difficulties/index.ts b/problems/difficulties/index.ts index ef73c65..279cc61 100644 --- a/problems/difficulties/index.ts +++ b/problems/difficulties/index.ts @@ -1 +1 @@ -export * as TransposeMatrix from './transpose-matrix'; +export * as TransposeMatrix from './1-transpose-matrix'; diff --git a/problems/tsconfig.json b/problems/tsconfig.json index a45e323..87fc9ad 100644 --- a/problems/tsconfig.json +++ b/problems/tsconfig.json @@ -1,9 +1,9 @@ { "extends": "../tsconfig.json", "compilerOptions": { - "baseUrl": ".", + "baseUrl": "..", "target": "ESNext", - "noImplicitAny": false + "noImplicitAny": false, }, "include": ["."], "exclude": [] diff --git a/src/components/Markdown/index.module.less b/src/components/Markdown/index.module.less index eb7ad06..18cf2a6 100644 --- a/src/components/Markdown/index.module.less +++ b/src/components/Markdown/index.module.less @@ -25,3 +25,9 @@ p > code { min-width: 32px !important; } } +.markdown-wrapper a { + color: rgb(var(--primary-6)) !important; + &:hover { + opacity: 0.8; + } +} diff --git a/src/components/Markdown/index.tsx b/src/components/Markdown/index.tsx index 02fb9ce..ac80b05 100644 --- a/src/components/Markdown/index.tsx +++ b/src/components/Markdown/index.tsx @@ -21,6 +21,7 @@ const Markdown = function (props: { const { content, theme } = props; return ( - - copyright © 2023-Present ZLY201 + + copyright © 2023-Present typescript-tutorial-exercises ); diff --git a/src/modules/Question/Records.tsx b/src/modules/Question/Records.tsx index 21aafe6..9598802 100644 --- a/src/modules/Question/Records.tsx +++ b/src/modules/Question/Records.tsx @@ -20,12 +20,12 @@ import i18nJson from '@config/i18n.json'; import styles from './index.module.less'; const Accepted = styled.div` - font-weight: 500; + font-weight: 600; color: rgb(var(--green-6)); `; const UnAccepted = styled.div` - font-weight: 500; + font-weight: 600; color: rgb(var(--red-6)); `; @@ -118,7 +118,6 @@ const Records = function () { render(_, item: ProblemRecord & { problem: string }) { return ( ); diff --git a/src/modules/Question/index.module.less b/src/modules/Question/index.module.less index 3969211..6dcbf37 100644 --- a/src/modules/Question/index.module.less +++ b/src/modules/Question/index.module.less @@ -36,7 +36,7 @@ .desc-title { width: 100%; font-size: 24px; - font-weight: 600; + font-weight: 700; display: flex; align-items: center; justify-content: space-between; @@ -59,7 +59,7 @@ } .desc-case-title { font-size: 18px; - font-weight: 600; + font-weight: 700; margin-bottom: 8px; } .desc-case-content { diff --git a/src/modules/Results/index.module.less b/src/modules/Results/index.module.less index 5a50b97..6a0e1db 100644 --- a/src/modules/Results/index.module.less +++ b/src/modules/Results/index.module.less @@ -53,7 +53,7 @@ margin-right: 16px; } &.arco-tabs-header-title-active { - font-weight: 500; + font-weight: 600; background-color: var(--color-fill-3); } } @@ -62,7 +62,7 @@ } .case-header { font-size: 16px; - font-weight: 500; + font-weight: 600; margin: 8px 0; } .case-input { @@ -94,7 +94,7 @@ height: 48px; line-height: 48px; font-size: 24px; - font-weight: 600; + font-weight: 700; margin-bottom: 16px; color: rgb(var(--red-6)); } diff --git a/tools/RspackSSRPlugin.ts b/tools/RspackSSRPlugin.ts index 17c4cb2..cabf4b5 100644 --- a/tools/RspackSSRPlugin.ts +++ b/tools/RspackSSRPlugin.ts @@ -45,6 +45,9 @@ class RspackSSRPlugin implements RspackPluginInstance { ]); buildProcess.stdout.on('data', process.stdout.write); buildProcess.stderr.on('data', process.stderr.write); + buildProcess.on('error', function (e) { + throw e; + }); buildProcess.on('close', function (code) { if (code === 0) { callback(); diff --git a/tools/addNewProblem.ts b/tools/addNewProblem.ts index 1768f2f..9c6f651 100644 --- a/tools/addNewProblem.ts +++ b/tools/addNewProblem.ts @@ -5,113 +5,249 @@ 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 = '') { +function handleStringWithDivider( + source: string, + divider = '', + separator = '-', + transformer: 'toUpperCase' | 'toLowerCase' = 'toUpperCase', +) { return source - .split('-') - .map(str => `${str[0].toUpperCase()}${str.slice(1)}`) + .split(separator) + .map(str => `${str[0][transformer]()}${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); +class AddProblemProcess { + private static NEW_TYPE_TAG = 'New problem type'; + private config: { + key?: string; + title?: string; + subject?: string; + subjectKey?: string; + author?: string; + } = {}; + private info: { + subjectDirName?: string; + problemDirName?: string; + } = {}; + private async getSubject() { + if (this.config.subject) { + return this.config.subject; + } + const subjects: string[] = []; + const subjectDirs = fs.readdirSync(PROBLEMS_PATH); + subjectDirs.forEach(function (dir) { + const stat = fs.lstatSync(path.resolve(PROBLEMS_PATH, dir)); + if (stat.isDirectory() === true) { + subjects.push(dir); + } + }); + const subjectChoices: prompts.Choice[] = subjects.map(subject => ({ + title: handleStringWithDivider(subject, ' '), + value: subject, + })); + subjectChoices.push({ + title: AddProblemProcess.NEW_TYPE_TAG, + value: AddProblemProcess.NEW_TYPE_TAG, + description: 'Add a new problem type', + }); + const { subject } = await prompts({ + type: 'select', + name: 'subject', + message: 'What is the subject of problem do you want to create?', + choices: subjectChoices, + }); + if (subject !== AddProblemProcess.NEW_TYPE_TAG) { + this.config.subject = handleStringWithDivider(subject, ' '); + this.info.subjectDirName = subject; + return this.config.subject; } - }); - 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({ + const { newSubject } = await prompts({ type: 'text', - name: 'newTypeName', - initial: 'template-type', - message: 'What is the name of the new type?', + name: 'newSubject', + initial: 'Template Type', + message: 'What is the name of the new subject?', + validate: value => { + const dirName = handleStringWithDivider(value, '-', ' ', 'toLowerCase'); + if (subjectDirs.includes(dirName)) { + return 'This subject already exists.'; + } + return Boolean(value); + }, + }); + this.config.subject = newSubject; + this.info.subjectDirName = handleStringWithDivider( + newSubject, + '-', + ' ', + 'toLowerCase', + ); + this.createNewSubject(); + return this.config.subject; + } + private async getSubjectKey() { + if (this.config.subjectKey) { + return this.config.subjectKey; + } + this.config.subjectKey = handleStringWithDivider( + this.config.subject!, + '', + ' ', + ); + return this.config.subjectKey!; + } + private async getTitle() { + if (this.config.title) { + return this.config.title; + } + const { subject } = this.config; + const { subjectDirName } = this.info; + const problemDirPath = path.resolve(PROBLEMS_PATH, subjectDirName!); + const problemsFiles = fs.readdirSync(problemDirPath); + const index = + problemsFiles.filter(function (item) { + const stat = fs.lstatSync(path.resolve(problemDirPath, item)); + return stat.isDirectory(); + }).length + 1; + const { title } = await prompts({ + type: 'text', + name: 'title', + message: 'What is the title of the new problem?', + initial: 'Template Problem', validate: value => - value === NEW_TYPE_TAG || types.includes(value) - ? 'This type already exists!' + problemJson.some( + problem => problem.subject === subject && problem.title === value, + ) + ? 'This problem already exists!' : Boolean(value), }); - fs.mkdirSync(path.resolve(PROBLEMS_PATH, newTypeName)); - problemType = newTypeName; + this.config.title = title; + this.info.problemDirName = `${index}-${handleStringWithDivider( + title, + '-', + ' ', + 'toLowerCase', + )}`; + return this.config.title!; } - 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.`, - ); + private async getKey() { + if (this.config.key) { + return this.config.key; + } + const { key } = await prompts({ + type: 'text', + name: 'key', + message: 'What is the special key of the new problem?', + validate: value => + problemJson.some(problem => problem.key === value) + ? 'This key already exists!' + : Boolean(value), + }); + this.config.key = key; + return this.config.key!; + } + private async getAuthor() { + if (this.config.author !== undefined) { + return this.config.author; + } + const { author = '' } = await prompts({ + type: 'text', + name: 'author', + message: 'Your github name to thanks:', + hint: 'Empty to hide this info in the page.', + }); + this.config.author = author; + return this.config.author!; + } + private createNewSubject() { + const { subjectKey } = this.config; + const { subjectDirName } = this.info; + const subjectDirPath = path.resolve(PROBLEMS_PATH, subjectDirName!); + fs.mkdirSync(subjectDirPath); + fs.writeFileSync(path.resolve(subjectDirPath, 'index.ts'), ''); + const rootIndexTsPath = path.resolve(PROBLEMS_PATH, 'index.ts'); + const rootIndexTs = fs.readFileSync(rootIndexTsPath); + fs.writeFileSync( + rootIndexTsPath, + `${rootIndexTs}export * as ${subjectKey} from './${subjectDirName}';\n`, + ); + } + private createNewProblem() { + const { key } = this.config; + const { subjectDirName, problemDirName } = this.info; + const subjectDirPath = path.resolve(PROBLEMS_PATH, subjectDirName!); + const problemDirPath = path.resolve(subjectDirPath!, problemDirName!); + fs.cpSync(HELLO_WORLD_PATH, problemDirPath, { recursive: true }); + const indexTsPath = path.resolve(subjectDirPath!, 'index.ts'); + const indexTs = fs.readFileSync(indexTsPath); + fs.writeFileSync( + indexTsPath, + `${indexTs}export * as ${key} from './${problemDirName}';\n`, + ); + } + private editConfigJson() { + problemJson.push({ ...(this.config as any) }); + fs.writeFileSync( + PROBLEM_JSON_PATH, + JSON.stringify(problemJson, undefined, 2), + { + encoding: 'utf-8', + }, + ); + } + private checkConfigValue(key: keyof typeof this.config) { + if (this.config[key] === undefined) { + console.error(chalk.red(`[error] ${key} doesn't exist.`)); + process.exit(1); + } + return true; + } + private log() { + const { subject, title } = this.config; + const { subjectDirName, problemDirName } = this.info; + console.log( + `The new problem ${chalk.underline.green( + `${subject}/${title}`, + )} has been created at ${chalk.underline.blue( + `problems/${subjectDirName}/${problemDirName}`, + )}.`, + ); + console.log( + `Please go ${chalk.blue.underline( + 'config/problems.json', + )} to edit the config of this new problem.`, + ); + } + async run() { + await this.getSubject(); + this.checkConfigValue('subject'); + + await this.getSubjectKey(); + this.checkConfigValue('subjectKey'); + + await this.getTitle(); + this.checkConfigValue('title'); + + await this.getKey(); + this.checkConfigValue('key'); + + await this.getAuthor(); + + this.createNewProblem(); + this.editConfigJson(); + + this.log(); + } +} + +async function main() { + await new AddProblemProcess().run(); } main();