chore: use constants for superblocks (#43886)

* chore: use constants for superblocks

* add prettier ts dec to challenge-helper-scripts

* config/ to ts. broken

* typescripterise tools/ and config/

* create global tsconfig, remove alternate configs

* delete temp ts->js, add to gitignore

* fix gitignore

* re-import SuperBlocks in super-block-intro.tsx

* remove renamed files added again

* fix config

* remove accidental files

* remove snap

* delete built files

* adjust eslintrc for enums

* add node types to root

* ignore build files in lint and prettier

* fix tools/ in tsconfig

* ignore annoying ts warnings

* prettierise Map/index.tsx

* fix enum to match lint rule

* rejig Map to render RWD superblock

* 'pretty minor' - implicitly tsc within root

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>

* fix client/package.json for Gitpod

* broken: migrate @types to root

* fix: use typeRoots to prevent duplication

* fix show.tsx, try typeroots in root

* silly fix for duplicate node_modules types

* remove typeRoots from root

* fix: tsconfig or not tsconfig, that is the...

* fix: ...question: Whether 'tis nobler in the mind

to suffer the slings and arrows of outrageous configs...

* fix: Or to take Arms against a Sea of lint errors
And by opposing end them

Co-authored-by: Oliver Eyton-Williams <ojeytonwilliams@gmail.com>
This commit is contained in:
Shaun Hamilton
2021-11-19 14:19:40 +00:00
committed by GitHub
parent d944fa0c8e
commit d75e43a1e7
29 changed files with 1391 additions and 262 deletions

View File

@ -4,3 +4,6 @@ client/public/**
api-server/src/public/**
api-server/lib/**
tools/contributor/**
tools/scripts/build/ensure-env.js
config/i18n/all-langs.js
config/certification-settings.js

View File

@ -45,9 +45,9 @@
"parser": "@typescript-eslint/parser",
"parserOptions": {
"project": [
"./client/tsconfig.json",
"./tools/challenge-helper-scripts/tsconfig.json",
"./tools/ui-components/tsconfig.json"
"./tsconfig.json",
"./tools/ui-components/tsconfig.json",
"./tools/scripts/build/tsconfig.json"
]
},
"extends": [
@ -91,6 +91,10 @@
{
"selector": "function",
"format": ["camelCase", "PascalCase"]
},
{
"selector": "enumMember",
"format": ["PascalCase"]
}
]
}

4
.gitignore vendored
View File

@ -163,6 +163,10 @@ config/client/sass-compile.json
config/client/frame-runner.json
config/client/test-evaluator.json
config/curriculum.json
config/i18n/all-langs.js
config/certification-settings.js
tools/scripts/build/ensure-env.js
### vim ###
# Swap

View File

@ -5,6 +5,9 @@ client/static
curriculum/challenges/_meta/*/*
curriculum/challenges/**/*
config/**/*.json
config/i18n/all-langs.js
config/certification-settings.js
client/i18n/**/*.json
docs/i18n
**/package-lock.json
tools/scripts/build/ensure-env.js

View File

@ -19,11 +19,11 @@
"author": "freeCodeCamp <team@freecodecamp.org>",
"main": "none",
"scripts": {
"prebuild": "node ../tools/scripts/build/ensure-env.js && npm run build:workers -- --env production",
"prebuild": "tsc -p ../tools/scripts/build/ && node ../tools/scripts/build/ensure-env.js && npm run build:workers -- --env production",
"build": "node --max_old_space_size=7168 node_modules/gatsby-cli build --prefix-paths",
"build:workers": "node --max_old_space_size=7168 node_modules/webpack-cli/bin/cli --config ./webpack-workers.js",
"clean": "gatsby clean",
"predevelop": "node ../tools/scripts/build/ensure-env.js && npm run build:workers -- --env development",
"predevelop": "tsc -p ../tools/scripts/build/ && node ../tools/scripts/build/ensure-env.js && npm run build:workers -- --env development",
"develop": "node --max_old_space_size=4000 node_modules/gatsby-cli develop --inspect=9230",
"lint": "node ./i18n/schema-validation.js",
"serve": "gatsby serve -p 8000",
@ -132,27 +132,6 @@
"@codesee/tracker": "0.143.0",
"@testing-library/jest-dom": "5.15.0",
"@testing-library/react": "12.1.2",
"@types/chai": "4.2.22",
"@types/jest": "26.0.24",
"@types/loadable__component": "5.13.4",
"@types/lodash-es": "4.17.5",
"@types/node": "16.11.7",
"@types/prismjs": "1.16.6",
"@types/psl": "1.1.0",
"@types/reach__router": "1.3.9",
"@types/react-dom": "17.0.11",
"@types/react-helmet": "6.1.4",
"@types/react-instantsearch-dom": "6.12.0",
"@types/react-monaco-editor": "0.16.0",
"@types/react-redux": "7.1.16",
"@types/react-responsive": "8.0.2",
"@types/react-spinkit": "3.0.7",
"@types/react-test-renderer": "17.0.1",
"@types/react-transition-group": "4.4.4",
"@types/redux-actions": "2.6.2",
"@types/sanitize-html": "2.5.0",
"@types/store": "2.0.2",
"@types/validator": "13.7.0",
"autoprefixer": "10.4.0",
"babel-plugin-transform-imports": "2.0.0",
"chokidar": "3.5.2",

View File

@ -1,4 +1,5 @@
import React from 'react';
import { SuperBlocks } from '../../../../config/certification-settings';
import APIIcon from './API-icon';
import D3Icon from './D3-icon';
import DatabaseIcon from './Database-icon';
@ -13,24 +14,22 @@ import ResponsiveDesign from './responsive-design';
import Shield from './shield';
const iconMap = {
'responsive-web-design': ResponsiveDesign,
'javascript-algorithms-and-data-structures': JavaScriptIcon,
'front-end-development-libraries': ReactIcon,
'data-visualization': D3Icon,
'back-end-development-and-apis': APIIcon,
'relational-databases': DatabaseIcon,
'quality-assurance': Clipboard,
'scientific-computing-with-python': PythonIcon,
'data-analysis-with-python': Analytics,
'information-security': Shield,
'machine-learning-with-python': TensorflowIcon,
'coding-interview-prep': Algorithm
[SuperBlocks.RespWebDesign]: ResponsiveDesign,
[SuperBlocks.JsAlgoDataStruct]: JavaScriptIcon,
[SuperBlocks.FrontEndDevLibs]: ReactIcon,
[SuperBlocks.DataVis]: D3Icon,
[SuperBlocks.BackEndDevApis]: APIIcon,
[SuperBlocks.RelationalDb]: DatabaseIcon,
[SuperBlocks.QualityAssurance]: Clipboard,
[SuperBlocks.SciCompPy]: PythonIcon,
[SuperBlocks.DataAnalysisPy]: Analytics,
[SuperBlocks.InfoSec]: Shield,
[SuperBlocks.MachineLearningPy]: TensorflowIcon,
[SuperBlocks.CodingInterviewPrep]: Algorithm
};
type SuperBlock = keyof typeof iconMap;
const generateIconComponent = (
superBlock: SuperBlock,
superBlock: SuperBlocks,
className: string
): JSX.Element => {
// fallback in case super block doesn't exist and for tests
@ -39,4 +38,4 @@ const generateIconComponent = (
return <Icon className={className} />;
};
export { generateIconComponent, SuperBlock };
export { generateIconComponent };

View File

@ -20,8 +20,8 @@ export const flashMessageSelector = (state: State): FlashState['message'] =>
// ACTION DEFINITIONS
enum FlashActionTypes {
createFlashMessage = 'createFlashMessage',
removeFlashMessage = 'removeFlashMessage'
CreateFlashMessage = 'createFlashMessage',
RemoveFlashMessage = 'removeFlashMessage'
}
export type FlashMessageArg = {
@ -32,7 +32,7 @@ export type FlashMessageArg = {
export const createFlashMessage = (
flash: FlashMessageArg
): ReducerPayload<FlashActionTypes.createFlashMessage> => {
): ReducerPayload<FlashActionTypes.CreateFlashMessage> => {
const playSound = store.get('fcc-sound') as boolean | undefined;
if (playSound) {
void import('tone').then(tone => {
@ -54,20 +54,20 @@ export const createFlashMessage = (
});
}
return {
type: FlashActionTypes.createFlashMessage,
type: FlashActionTypes.CreateFlashMessage,
payload: { ...flash, id: nanoid() }
};
};
export const removeFlashMessage =
(): ReducerPayload<FlashActionTypes.removeFlashMessage> => ({
type: FlashActionTypes.removeFlashMessage
(): ReducerPayload<FlashActionTypes.RemoveFlashMessage> => ({
type: FlashActionTypes.RemoveFlashMessage
});
// REDUCER
type ReducerBase<T> = { type: T };
type ReducerPayload<T extends FlashActionTypes> =
T extends FlashActionTypes.createFlashMessage
T extends FlashActionTypes.CreateFlashMessage
? ReducerBase<T> & {
payload: FlashState['message'];
}
@ -79,9 +79,9 @@ export const reducer = (
action: ReducerPayload<FlashActionTypes>
): FlashState => {
switch (action.type) {
case FlashActionTypes.createFlashMessage:
case FlashActionTypes.CreateFlashMessage:
return { ...state, message: action.payload };
case FlashActionTypes.removeFlashMessage:
case FlashActionTypes.RemoveFlashMessage:
return { ...state, message: initialState.message };
default:
return state;

View File

@ -2,9 +2,10 @@ import { graphql, useStaticQuery } from 'gatsby';
import i18next from 'i18next';
import React from 'react';
import { SuperBlocks } from '../../../../config/certification-settings';
import envData from '../../../../config/env.json';
import { isAuditedCert } from '../../../../utils/is-audited';
import { generateIconComponent, SuperBlock } from '../../assets/icons';
import { generateIconComponent } from '../../assets/icons';
import LinkButton from '../../assets/icons/link-button';
import { ChallengeNode } from '../../redux/prop-types';
import { Link, Spacer } from '../helpers';
@ -14,7 +15,7 @@ import './map.css';
const { curriculumLocale } = envData;
interface MapProps {
currentSuperBlock?: string;
currentSuperBlock?: SuperBlocks | null;
forLanding?: boolean;
}
@ -24,7 +25,7 @@ interface MapData {
};
}
function createSuperBlockTitle(superBlock: string) {
function createSuperBlockTitle(superBlock: SuperBlocks) {
const superBlockTitle = i18next.t(`intro:${superBlock}.title`);
return superBlock === 'coding-interview-prep'
? i18next.t('learn.cert-map-estimates.coding-prep', {
@ -40,7 +41,9 @@ const linkSpacingStyle = {
};
function renderLandingMap(nodes: ChallengeNode[]) {
nodes = nodes.filter(node => node.superBlock !== 'coding-interview-prep');
nodes = nodes.filter(
node => node.superBlock !== SuperBlocks.CodingInterviewPrep
);
return (
<ul data-test-label='certifications'>
{nodes.map((node, i) => (
@ -50,7 +53,7 @@ function renderLandingMap(nodes: ChallengeNode[]) {
to={`/learn/${node.superBlock}/`}
>
<div style={linkSpacingStyle}>
{generateIconComponent(node.superBlock as SuperBlock, 'map-icon')}
{generateIconComponent(node.superBlock, 'map-icon')}
{i18next.t(`intro:${node.superBlock}.title`)}
</div>
<LinkButton />
@ -61,7 +64,10 @@ function renderLandingMap(nodes: ChallengeNode[]) {
);
}
function renderLearnMap(nodes: ChallengeNode[], currentSuperBlock = '') {
function renderLearnMap(
nodes: ChallengeNode[],
currentSuperBlock: MapProps['currentSuperBlock']
) {
nodes = nodes.filter(node => node.superBlock !== currentSuperBlock);
return curriculumLocale === 'english' ? (
<ul data-test-label='learn-curriculum-map'>
@ -72,7 +78,7 @@ function renderLearnMap(nodes: ChallengeNode[], currentSuperBlock = '') {
to={`/learn/${node.superBlock}/`}
>
<div style={linkSpacingStyle}>
{generateIconComponent(node.superBlock as SuperBlock, 'map-icon')}
{generateIconComponent(node.superBlock, 'map-icon')}
{createSuperBlockTitle(node.superBlock)}
</div>
</Link>
@ -90,10 +96,7 @@ function renderLearnMap(nodes: ChallengeNode[], currentSuperBlock = '') {
to={`/learn/${node.superBlock}/`}
>
<div style={linkSpacingStyle}>
{generateIconComponent(
node.superBlock as SuperBlock,
'map-icon'
)}
{generateIconComponent(node.superBlock, 'map-icon')}
{createSuperBlockTitle(node.superBlock)}
</div>
</Link>
@ -120,10 +123,7 @@ function renderLearnMap(nodes: ChallengeNode[], currentSuperBlock = '') {
to={`/learn/${node.superBlock}/`}
>
<div style={linkSpacingStyle}>
{generateIconComponent(
node.superBlock as SuperBlock,
'map-icon'
)}
{generateIconComponent(node.superBlock, 'map-icon')}
{createSuperBlockTitle(node.superBlock)}
</div>
</Link>
@ -135,7 +135,7 @@ function renderLearnMap(nodes: ChallengeNode[], currentSuperBlock = '') {
export function Map({
forLanding = false,
currentSuperBlock = ''
currentSuperBlock = null
}: MapProps): React.ReactElement {
/*
* this query gets the first challenge from each block and the second block

View File

@ -2,6 +2,7 @@ import { uniqBy } from 'lodash-es';
import { createAction, handleActions } from 'redux-actions';
import store from 'store';
import { SuperBlocks } from '../../../config/certification-settings';
import { actionTypes as challengeTypes } from '../templates/Challenges/redux/action-types';
import { CURRENT_CHALLENGE_KEY } from '../templates/Challenges/redux/current-challenge-saga';
import { createAcceptTermsSaga } from './accept-terms-saga';
@ -292,27 +293,27 @@ export const certificatesByNameSelector = username => state => {
{
show: isRespWebDesignCert,
title: 'Responsive Web Design Certification',
certSlug: 'responsive-web-design'
certSlug: SuperBlocks.RespWebDesign
},
{
show: isJsAlgoDataStructCert,
title: 'JavaScript Algorithms and Data Structures Certification',
certSlug: 'javascript-algorithms-and-data-structures'
certSlug: SuperBlocks.JsAlgoDataStruct
},
{
show: isFrontEndLibsCert,
title: 'Front End Development Libraries Certification',
certSlug: 'front-end-development-libraries'
certSlug: SuperBlocks.FrontEndDevLibs
},
{
show: is2018DataVisCert,
title: 'Data Visualization Certification',
certSlug: 'data-visualization'
certSlug: SuperBlocks.DataVis
},
{
show: isApisMicroservicesCert,
title: 'Back End Development and APIs Certification',
certSlug: 'back-end-development-and-apis'
certSlug: SuperBlocks.BackEndDevApis
},
{
show: isQaCertV7,

View File

@ -1,5 +1,6 @@
import PropTypes from 'prop-types';
import { HandlerProps } from 'react-reflex';
import { SuperBlocks } from '../../../config/certification-settings';
export const UserPropType = PropTypes.shape({
about: PropTypes.string,
@ -81,7 +82,7 @@ export type MarkdownRemark = {
frontmatter: {
block: string;
isBeta: boolean;
superBlock: string;
superBlock: SuperBlocks;
title: string;
};
headings: [
@ -159,7 +160,7 @@ export type ChallengeNode = {
};
sourceInstanceName: string;
superOrder: number;
superBlock: string;
superBlock: SuperBlocks;
tail: string[];
template: string;
tests: Test[];
@ -302,7 +303,7 @@ export type ChallengeMeta = {
nextChallengePath: string;
prevChallengePath: string;
removeComments: boolean;
superBlock: string;
superBlock: SuperBlocks;
title?: string;
challengeType?: number;
helpCategory: string;

View File

@ -1,3 +1,5 @@
import { SuperBlocks } from '../../../config/certification-settings';
const responsiveWebBase =
'/learn/responsive-web-design/responsive-web-design-projects';
const jsAlgoBase =
@ -289,228 +291,228 @@ const certMap = [
{
id: '561add10cb82ac38a17513bc',
title: 'Responsive Web Design',
certSlug: 'responsive-web-design',
certSlug: SuperBlocks.RespWebDesign,
flag: 'isRespWebDesignCert',
projects: [
{
id: 'bd7158d8c442eddfaeb5bd18',
title: 'Build a Tribute Page',
link: `${responsiveWebBase}/build-a-tribute-page`,
certSlug: 'responsive-web-design'
certSlug: SuperBlocks.RespWebDesign
},
{
id: '587d78af367417b2b2512b03',
title: 'Build a Survey Form',
link: `${responsiveWebBase}/build-a-survey-form`,
certSlug: 'responsive-web-design'
certSlug: SuperBlocks.RespWebDesign
},
{
id: '587d78af367417b2b2512b04',
title: 'Build a Product Landing Page',
link: `${responsiveWebBase}/build-a-product-landing-page`,
certSlug: 'responsive-web-design'
certSlug: SuperBlocks.RespWebDesign
},
{
id: '587d78b0367417b2b2512b05',
title: 'Build a Technical Documentation Page',
link: `${responsiveWebBase}/build-a-technical-documentation-page`,
certSlug: 'responsive-web-design'
certSlug: SuperBlocks.RespWebDesign
},
{
id: 'bd7158d8c242eddfaeb5bd13',
title: 'Build a Personal Portfolio Webpage',
link: `${responsiveWebBase}/build-a-personal-portfolio-webpage`,
certSlug: 'responsive-web-design'
certSlug: SuperBlocks.RespWebDesign
}
]
},
{
id: '561abd10cb81ac38a17513bc',
title: 'JavaScript Algorithms and Data Structures',
certSlug: 'javascript-algorithms-and-data-structures',
certSlug: SuperBlocks.JsAlgoDataStruct,
flag: 'isJsAlgoDataStructCert',
projects: [
{
id: 'aaa48de84e1ecc7c742e1124',
title: 'Palindrome Checker',
link: `${jsAlgoBase}/palindrome-checker`,
certSlug: 'javascript-algorithms-and-data-structures'
certSlug: SuperBlocks.JsAlgoDataStruct
},
{
id: 'a7f4d8f2483413a6ce226cac',
title: 'Roman Numeral Converter',
link: `${jsAlgoBase}/roman-numeral-converter`,
certSlug: 'javascript-algorithms-and-data-structures'
certSlug: SuperBlocks.JsAlgoDataStruct
},
{
id: '56533eb9ac21ba0edf2244e2',
title: 'Caesars Cipher',
link: `${jsAlgoBase}/caesars-cipher`,
certSlug: 'javascript-algorithms-and-data-structures'
certSlug: SuperBlocks.JsAlgoDataStruct
},
{
id: 'aff0395860f5d3034dc0bfc9',
title: 'Telephone Number Validator',
link: `${jsAlgoBase}/telephone-number-validator`,
certSlug: 'javascript-algorithms-and-data-structures'
certSlug: SuperBlocks.JsAlgoDataStruct
},
{
id: 'aa2e6f85cab2ab736c9a9b24',
title: 'Cash Register',
link: `${jsAlgoBase}/cash-register`,
certSlug: 'javascript-algorithms-and-data-structures'
certSlug: SuperBlocks.JsAlgoDataStruct
}
]
},
{
id: '561acd10cb82ac38a17513bc',
title: 'Front End Development Libraries',
certSlug: 'front-end-development-libraries',
certSlug: SuperBlocks.FrontEndDevLibs,
flag: 'isFrontEndLibsCert',
projects: [
{
id: 'bd7158d8c442eddfaeb5bd13',
title: 'Build a Random Quote Machine',
link: `${feLibsBase}/build-a-random-quote-machine`,
certSlug: 'front-end-development-libraries'
certSlug: SuperBlocks.FrontEndDevLibs
},
{
id: 'bd7157d8c242eddfaeb5bd13',
title: 'Build a Markdown Previewer',
link: `${feLibsBase}/build-a-markdown-previewer`,
certSlug: 'front-end-development-libraries'
certSlug: SuperBlocks.FrontEndDevLibs
},
{
id: '587d7dbc367417b2b2512bae',
title: 'Build a Drum Machine',
link: `${feLibsBase}/build-a-drum-machine`,
certSlug: 'front-end-development-libraries'
certSlug: SuperBlocks.FrontEndDevLibs
},
{
id: 'bd7158d8c442eddfaeb5bd17',
title: 'Build a JavaScript Calculator',
link: `${feLibsBase}/build-a-javascript-calculator`,
certSlug: 'front-end-development-libraries'
certSlug: SuperBlocks.FrontEndDevLibs
},
{
id: 'bd7158d8c442eddfaeb5bd0f',
title: 'Build a 25 + 5 Clock',
link: `${feLibsBase}/build-a-25--5-clock`,
certSlug: 'front-end-development-libraries'
certSlug: SuperBlocks.FrontEndDevLibs
}
]
},
{
id: '5a553ca864b52e1d8bceea14',
title: 'Data Visualization',
certSlug: 'data-visualization',
certSlug: SuperBlocks.DataVis,
flag: 'is2018DataVisCert',
projects: [
{
id: 'bd7168d8c242eddfaeb5bd13',
title: 'Visualize Data with a Bar Chart',
link: `${dataVisBase}/visualize-data-with-a-bar-chart`,
certSlug: 'data-visualization'
certSlug: SuperBlocks.DataVis
},
{
id: 'bd7178d8c242eddfaeb5bd13',
title: 'Visualize Data with a Scatterplot Graph',
link: `${dataVisBase}/visualize-data-with-a-scatterplot-graph`,
certSlug: 'data-visualization'
certSlug: SuperBlocks.DataVis
},
{
id: 'bd7188d8c242eddfaeb5bd13',
title: 'Visualize Data with a Heat Map',
link: `${dataVisBase}/visualize-data-with-a-heat-map`,
certSlug: 'data-visualization'
certSlug: SuperBlocks.DataVis
},
{
id: '587d7fa6367417b2b2512bbf',
title: 'Visualize Data with a Choropleth Map',
link: `${dataVisBase}/visualize-data-with-a-choropleth-map`,
certSlug: 'data-visualization'
certSlug: SuperBlocks.DataVis
},
{
id: '587d7fa6367417b2b2512bc0',
title: 'Visualize Data with a Treemap Diagram',
link: `${dataVisBase}/visualize-data-with-a-treemap-diagram`,
certSlug: 'data-visualization'
certSlug: SuperBlocks.DataVis
}
]
},
{
id: '606243f50267e718b1e755f4',
title: 'Relational Databases',
certSlug: 'relational-databases',
certSlug: SuperBlocks.RelationalDb,
flag: 'isRelationalDatabasesCert',
projects: [
{
id: '5f1a4ef5d5d6b5ab580fc6ae',
title: 'Celestial Bodies Database',
link: `${relationalDatabasesBase}/celestial-bodies-database`,
superBlock: 'relational-databases'
superBlock: SuperBlocks.RelationalDb
},
{
id: '5f87ac112ae598023a42df1a',
title: 'Salon Appointment Scheduler',
link: `${relationalDatabasesBase}/salon-appointment-scheduler`,
superBlock: 'relational-databases'
superBlock: SuperBlocks.RelationalDb
},
{
id: '5f9771307d4d22b9d2b75a94',
title: 'World Cup Database',
link: `${relationalDatabasesBase}/world-cup-database`,
superBlock: 'relational-databases'
superBlock: SuperBlocks.RelationalDb
},
{
id: '602d9ff222201c65d2a019f2',
title: 'Periodic Table Database',
link: `${relationalDatabasesBase}/periodic-table-database`,
superBlock: 'relational-databases'
superBlock: SuperBlocks.RelationalDb
},
{
id: '602da04c22201c65d2a019f4',
title: 'Number Guessing Game',
link: `${relationalDatabasesBase}/number-guessing-game`,
superBlock: 'relational-databases'
superBlock: SuperBlocks.RelationalDb
}
]
},
{
id: '561add10cb82ac38a17523bc',
title: 'Back End Development and APIs',
certSlug: 'back-end-development-and-apis',
certSlug: SuperBlocks.BackEndDevApis,
flag: 'isApisMicroservicesCert',
projects: [
{
id: 'bd7158d8c443edefaeb5bdef',
title: 'Timestamp Microservice',
link: `${apiMicroBase}/timestamp-microservice`,
certSlug: 'back-end-development-and-apis'
certSlug: SuperBlocks.BackEndDevApis
},
{
id: 'bd7158d8c443edefaeb5bdff',
title: 'Request Header Parser Microservice',
link: `${apiMicroBase}/request-header-parser-microservice`,
certSlug: 'back-end-development-and-apis'
certSlug: SuperBlocks.BackEndDevApis
},
{
id: 'bd7158d8c443edefaeb5bd0e',
title: 'URL Shortener Microservice',
link: `${apiMicroBase}/url-shortener-microservice`,
certSlug: 'back-end-development-and-apis'
certSlug: SuperBlocks.BackEndDevApis
},
{
id: '5a8b073d06fa14fcfde687aa',
title: 'Exercise Tracker',
link: `${apiMicroBase}/exercise-tracker`,
certSlug: 'back-end-development-and-apis'
certSlug: SuperBlocks.BackEndDevApis
},
{
id: 'bd7158d8c443edefaeb5bd0f',
title: 'File Metadata Microservice',
link: `${apiMicroBase}/file-metadata-microservice`,
certSlug: 'back-end-development-and-apis'
certSlug: SuperBlocks.BackEndDevApis
}
]
},

View File

@ -333,7 +333,6 @@ class ShowClassic extends Component<ShowClassicProps, ShowClassicState> {
containerRef={this.containerRef}
description={description}
editorRef={this.editorRef}
hasEditableBoundaries={this.hasEditableBoundaries()}
initialTests={tests}
resizeProps={this.resizeProps}
title={title}

View File

@ -1,12 +1,14 @@
import { render, fireEvent, screen } from '@testing-library/react';
import React from 'react';
import { SuperBlocks } from '../../../../../config/certification-settings';
import CompletionModalBody from './completion-modal-body';
const props = {
block: 'basic-html-and-html5',
completedPercent: Math.floor(Math.random() * 101),
superBlock: 'responsive-web-design'
superBlock: SuperBlocks.RespWebDesign
};
describe('<CompletionModalBody />', () => {

View File

@ -10,6 +10,7 @@ import { configureAnchors } from 'react-scrollable-anchor';
import { bindActionCreators, Dispatch } from 'redux';
import { createSelector } from 'reselect';
import { SuperBlocks } from '../../../../config/certification-settings';
import DonateModal from '../../components/Donation/DonationModal';
import Login from '../../components/Header/components/Login';
import Map from '../../components/Map';
@ -172,7 +173,7 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
const blockDashedNames = uniq(nodesForSuperBlock.map(({ block }) => block));
const i18nSuperBlock = t(`intro:${superBlock}.title`);
const i18nTitle =
superBlock === 'coding-interview-prep'
superBlock === SuperBlocks.CodingInterviewPrep
? i18nSuperBlock
: t(`intro:misc-text.certification`, {
cert: i18nSuperBlock
@ -209,7 +210,7 @@ const SuperBlockIntroductionPage = (props: SuperBlockProp) => {
{blockDashedName !== 'project-euler' ? <Spacer /> : null}
</Fragment>
))}
{superBlock !== 'coding-interview-prep' && (
{superBlock !== SuperBlocks.CodingInterviewPrep && (
<div>
<CertChallenge
superBlock={superBlock}

View File

@ -1,4 +1,4 @@
const certTypes = {
export const certTypes = {
frontEnd: 'isFrontEndCert',
backEnd: 'isBackEndCert',
dataVis: 'isDataVisCert',
@ -17,7 +17,22 @@ const certTypes = {
relationalDatabasesV8: 'isRelationalDatabasesCertV8'
};
const certIds = {
export enum SuperBlocks {
RespWebDesign = 'responsive-web-design',
JsAlgoDataStruct = 'javascript-algorithms-and-data-structures',
FrontEndDevLibs = 'front-end-development-libraries',
DataVis = 'data-visualization',
RelationalDb = 'relational-databases',
BackEndDevApis = 'back-end-development-and-apis',
QualityAssurance = 'quality-assurance',
SciCompPy = 'scientific-computing-with-python',
DataAnalysisPy = 'data-analysis-with-python',
InfoSec = 'information-security',
MachineLearningPy = 'machine-learning-with-python',
CodingInterviewPrep = 'coding-interview-prep'
}
export const certIds = {
legacyFrontEndChallengeId: '561add10cb82ac38a17513be',
legacyBackEndChallengeId: '660add10cb82ac38a17513be',
legacyDataVisId: '561add10cb82ac39a17513bc',
@ -36,7 +51,7 @@ const certIds = {
relationalDatabasesV8Id: '606243f50267e718b1e755f4'
};
const completionHours = {
export const completionHours = {
[certTypes.frontEnd]: 400,
[certTypes.backEnd]: 400,
[certTypes.dataVis]: 400,
@ -55,7 +70,7 @@ const completionHours = {
[certTypes.relationalDatabasesV8]: 300
};
const certSlugTypeMap = {
export const certSlugTypeMap = {
// legacy
'legacy-front-end': certTypes.frontEnd,
'legacy-back-end': certTypes.backEnd,
@ -66,11 +81,11 @@ const certSlugTypeMap = {
'full-stack': certTypes.fullStack,
// modern
'responsive-web-design': certTypes.respWebDesign,
'javascript-algorithms-and-data-structures': certTypes.jsAlgoDataStruct,
'front-end-development-libraries': certTypes.frontEndDevLibs,
'data-visualization': certTypes.dataVis2018,
'back-end-development-and-apis': certTypes.apisMicroservices,
[SuperBlocks.RespWebDesign]: certTypes.respWebDesign,
[SuperBlocks.JsAlgoDataStruct]: certTypes.jsAlgoDataStruct,
[SuperBlocks.FrontEndDevLibs]: certTypes.frontEndDevLibs,
[SuperBlocks.DataVis]: certTypes.dataVis2018,
[SuperBlocks.BackEndDevApis]: certTypes.apisMicroservices,
'quality-assurance-v7': certTypes.qaV7,
'information-security-v7': certTypes.infosecV7,
'scientific-computing-with-python-v7': certTypes.sciCompPyV7,
@ -79,7 +94,7 @@ const certSlugTypeMap = {
'relational-databases-v8': certTypes.relationalDatabasesV8
};
const superBlockCertTypeMap = {
export const superBlockCertTypeMap = {
// legacy
'legacy-front-end': certTypes.frontEnd,
'legacy-back-end': certTypes.backEnd,
@ -88,20 +103,20 @@ const superBlockCertTypeMap = {
'full-stack': certTypes.fullStack,
// modern
'responsive-web-design': certTypes.respWebDesign,
'javascript-algorithms-and-data-structures': certTypes.jsAlgoDataStruct,
'front-end-development-libraries': certTypes.frontEndDevLibs,
'data-visualization': certTypes.dataVis2018,
'back-end-development-and-apis': certTypes.apisMicroservices,
'quality-assurance': certTypes.qaV7,
'information-security': certTypes.infosecV7,
'scientific-computing-with-python': certTypes.sciCompPyV7,
'data-analysis-with-python': certTypes.dataAnalysisPyV7,
'machine-learning-with-python': certTypes.machineLearningPyV7,
'relational-databases': certTypes.relationalDatabasesV8
[SuperBlocks.RespWebDesign]: certTypes.respWebDesign,
[SuperBlocks.JsAlgoDataStruct]: certTypes.jsAlgoDataStruct,
[SuperBlocks.FrontEndDevLibs]: certTypes.frontEndDevLibs,
[SuperBlocks.DataVis]: certTypes.dataVis2018,
[SuperBlocks.BackEndDevApis]: certTypes.apisMicroservices,
[SuperBlocks.QualityAssurance]: certTypes.qaV7,
[SuperBlocks.InfoSec]: certTypes.infosecV7,
[SuperBlocks.SciCompPy]: certTypes.sciCompPyV7,
[SuperBlocks.DataAnalysisPy]: certTypes.dataAnalysisPyV7,
[SuperBlocks.MachineLearningPy]: certTypes.machineLearningPyV7,
[SuperBlocks.RelationalDb]: certTypes.relationalDatabasesV8
};
const certTypeIdMap = {
export const certTypeIdMap = {
[certTypes.frontEnd]: certIds.legacyFrontEndChallengeId,
[certTypes.backEnd]: certIds.legacyBackEndChallengeId,
[certTypes.dataVis]: certIds.legacyDataVisId,
@ -120,7 +135,7 @@ const certTypeIdMap = {
[certTypes.relationalDatabasesV8]: certIds.relationalDatabasesV8Id
};
const certTypeTitleMap = {
export const certTypeTitleMap = {
[certTypes.frontEnd]: 'Legacy Front End',
[certTypes.backEnd]: 'Legacy Back End',
[certTypes.dataVis]: 'Legacy Data Visualization',
@ -139,11 +154,4 @@ const certTypeTitleMap = {
[certTypes.relationalDatabasesV8]: 'Relational Databases'
};
exports.oldDataVizId = '561add10cb82ac38a17513b3';
exports.completionHours = completionHours;
exports.certTypes = certTypes;
exports.superBlockCertTypeMap = superBlockCertTypeMap;
exports.certSlugTypeMap = certSlugTypeMap;
exports.certIds = certIds;
exports.certTypeIdMap = certTypeIdMap;
exports.certTypeTitleMap = certTypeTitleMap;
export const oldDataVizId = '561add10cb82ac38a17513b3';

View File

@ -1,5 +1,5 @@
// ---------------------------------------------------------------------------
import { SuperBlocks } from '../certification-settings';
/*
* List of languages with localizations enabled for builds.
*
@ -8,7 +8,7 @@
* An error will be thrown if the CLIENT_LOCALE and CURRICULUM_LOCALE variables
* from the .env file aren't found in their respective arrays below
*/
const availableLangs = {
export const availableLangs = {
client: [
'english',
'espanol',
@ -35,61 +35,61 @@ const availableLangs = {
* certifications which have not been audited & approved will fallback to
* English equivalent.
*/
const auditedCerts = {
export const auditedCerts = {
espanol: [
'responsive-web-design',
'javascript-algorithms-and-data-structures',
'front-end-development-libraries',
'data-visualization',
'back-end-development-and-apis'
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis
],
chinese: [
'responsive-web-design',
'javascript-algorithms-and-data-structures',
'front-end-development-libraries',
'data-visualization',
'back-end-development-and-apis',
'quality-assurance',
'scientific-computing-with-python',
'data-analysis-with-python',
'information-security',
'machine-learning-with-python'
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
],
'chinese-traditional': [
'responsive-web-design',
'javascript-algorithms-and-data-structures',
'front-end-development-libraries',
'data-visualization',
'back-end-development-and-apis',
'quality-assurance',
'scientific-computing-with-python',
'data-analysis-with-python',
'information-security',
'machine-learning-with-python'
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
],
italian: [
'responsive-web-design',
'javascript-algorithms-and-data-structures',
'front-end-development-libraries',
'data-visualization',
'back-end-development-and-apis',
'quality-assurance',
'scientific-computing-with-python',
'data-analysis-with-python',
'information-security',
'machine-learning-with-python'
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
],
portuguese: [
'responsive-web-design',
'javascript-algorithms-and-data-structures',
'front-end-development-libraries',
'data-visualization',
'back-end-development-and-apis',
'quality-assurance',
'scientific-computing-with-python',
'data-analysis-with-python',
'information-security',
'machine-learning-with-python'
SuperBlocks.RespWebDesign,
SuperBlocks.JsAlgoDataStruct,
SuperBlocks.FrontEndDevLibs,
SuperBlocks.DataVis,
SuperBlocks.BackEndDevApis,
SuperBlocks.QualityAssurance,
SuperBlocks.SciCompPy,
SuperBlocks.DataAnalysisPy,
SuperBlocks.InfoSec,
SuperBlocks.MachineLearningPy
]
};
@ -101,7 +101,7 @@ const auditedCerts = {
* string for the language to take advantage of available functionality.
* Use a 639-1 code here https://en.wikipedia.org/wiki/List_of_ISO_639-1_codes
*/
const i18nextCodes = {
export const i18nextCodes = {
english: 'en',
espanol: 'es',
chinese: 'zh',
@ -111,7 +111,7 @@ const i18nextCodes = {
};
// These are for the language selector dropdown menu in the footer
const langDisplayNames = {
export const langDisplayNames = {
english: 'English',
espanol: 'Español',
chinese: '中文(简体字)',
@ -124,7 +124,7 @@ const langDisplayNames = {
* There's an example in profile/components/Camper.js
* List: https://github.com/unicode-cldr/cldr-dates-modern/tree/master/main
*/
const langCodes = {
export const langCodes = {
english: 'en-US',
espanol: 'es-419',
chinese: 'zh',
@ -132,9 +132,3 @@ const langCodes = {
italian: 'it',
portuguese: 'pt-BR'
};
exports.availableLangs = availableLangs;
exports.i18nextCodes = i18nextCodes;
exports.langDisplayNames = langDisplayNames;
exports.langCodes = langCodes;
exports.auditedCerts = auditedCerts;

View File

@ -1,6 +1,8 @@
import { SuperBlocks } from '../../config/certification-settings';
const certificationUrl = '/certification/developmentuser/responsive-web-design';
const projects = {
superBlock: 'responsive-web-design',
superBlock: SuperBlocks.RespWebDesign,
block: 'responsive-web-design-projects',
challenges: [
{

View File

@ -1,11 +1,12 @@
/* global cy */
import { SuperBlocks } from '../../../../config/certification-settings';
const selectors = {
editor: '.react-monaco-editor-container'
};
const pythonProjects = {
superBlock: 'machine-learning-with-python',
superBlock: SuperBlocks.MachineLearningPy,
block: 'machine-learning-with-python-projects',
challenges: [
{
@ -64,7 +65,7 @@ describe('project submission', () => {
cy.login();
cy.fixture('../../config/curriculum.json').then(curriculum => {
const { challenges, meta } =
curriculum['javascript-algorithms-and-data-structures'].blocks[
curriculum[SuperBlocks.JsAlgoDataStruct].blocks[
'javascript-algorithms-and-data-structures-projects'
];

View File

@ -1,5 +1,7 @@
import { SuperBlocks } from '../../../../config/certification-settings';
const projects = {
superBlock: 'responsive-web-design',
superBlock: SuperBlocks.RespWebDesign,
block: 'responsive-web-design-projects',
challenges: [
{

1103
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -55,7 +55,7 @@
"e2e:dev:watch": "start-test develop ':3000/status/ping|8000' cypress:dev:watch",
"e2e:prd:run": "npm run build && start-test ':3000/status/ping|8000' cypress:dev:run",
"e2e:prd:watch": "npm run build && start-test ':3000/status/ping|8000' cypress:dev:watch",
"ensure-env": "cross-env DEBUG=fcc:* node ./tools/scripts/build/ensure-env.js",
"ensure-env": "cross-env DEBUG=fcc:* tsc ./tools/scripts/build/ensure-env.ts && node ./tools/scripts/build/ensure-env.js",
"format": "run-s format:eslint format:prettier",
"format:eslint": "eslint . --fix",
"format:prettier": "prettier --write .",
@ -64,7 +64,7 @@
"lint": "npm-run-all ensure-env -p lint:*",
"lint:challenges": "cd ./curriculum && npm run lint",
"lint:js": "eslint --max-warnings 0 .",
"lint:ts": "tsc -p client && tsc -p tools/ui-components",
"lint:ts": "tsc && tsc -p tools/ui-components && tsc -p tools/scripts/build",
"lint:prettier": "prettier --list-different .",
"postinstall": "npm run bootstrap",
"seed": "cross-env DEBUG=fcc:* node ./tools/scripts/seed/seedAuthUser",
@ -101,6 +101,29 @@
"@testing-library/dom": "8.11.1",
"@testing-library/jest-dom": "5.15.0",
"@testing-library/user-event": "13.5.0",
"@types/chai": "^4.2.22",
"@types/inquirer": "^8.1.3",
"@types/jest": "^27.0.2",
"@types/loadable__component": "^5.13.4",
"@types/lodash-es": "^4.17.5",
"@types/node": "^16.11.7",
"@types/prismjs": "^1.16.6",
"@types/psl": "^1.1.0",
"@types/reach__router": "^1.3.9",
"@types/react": "^17.0.35",
"@types/react-dom": "^17.0.11",
"@types/react-helmet": "^6.1.4",
"@types/react-instantsearch-dom": "^6.12.0",
"@types/react-monaco-editor": "^0.16.0",
"@types/react-redux": "^7.1.20",
"@types/react-responsive": "^8.0.4",
"@types/react-spinkit": "^3.0.7",
"@types/react-test-renderer": "^17.0.1",
"@types/react-transition-group": "^4.4.4",
"@types/redux-actions": "^2.6.2",
"@types/sanitize-html": "^2.5.0",
"@types/store": "^2.0.2",
"@types/validator": "^13.7.0",
"@typescript-eslint/eslint-plugin": "4.33.0",
"@typescript-eslint/parser": "4.33.0",
"babel-eslint": "10.1.0",

View File

@ -4,25 +4,10 @@ import path from 'path';
import { prompt } from 'inquirer';
import { format } from 'prettier';
import { SuperBlocks } from '../../config/certification-settings';
import { blockNameify } from '../../utils/block-nameify';
import { createStepFile } from './utils.js';
const superBlocks = [
'responsive-web-design',
'javascript-algorithms-and-data-structures',
'front-end-development-libraries',
'data-visualization',
'back-end-development-and-apis',
'quality-assurance',
'scientific-computing-with-python',
'data-analysis-with-python',
'information-security',
'machine-learning-with-python',
'coding-interview-prep'
] as const;
type SuperBlock = typeof superBlocks[number];
const helpCategories = ['HTML-CSS', 'JavaScript', 'Python'] as const;
type BlockInfo = {
@ -34,7 +19,7 @@ type SuperBlockInfo = {
blocks: Record<string, BlockInfo>;
};
type IntroJson = Record<SuperBlock, SuperBlockInfo>;
type IntroJson = Record<SuperBlocks, SuperBlockInfo>;
type Meta = {
name: string;
@ -51,7 +36,7 @@ type Meta = {
};
async function createProject(
superBlock: SuperBlock,
superBlock: SuperBlocks,
block: string,
helpCategory: string,
order: number,
@ -86,7 +71,7 @@ async function createProject(
}
async function updateIntroJson(
superBlock: SuperBlock,
superBlock: SuperBlocks,
block: string,
title: string
) {
@ -138,7 +123,7 @@ async function updateBlockNames(block: string, title: string) {
}
async function createMetaJson(
superBlock: SuperBlock,
superBlock: SuperBlocks,
block: string,
title: string,
order: number,
@ -149,7 +134,7 @@ async function createMetaJson(
newMeta.name = title;
newMeta.dashedName = block;
newMeta.order = order;
newMeta.superOrder = superBlocks.indexOf(superBlock) + 1;
newMeta.superOrder = Object.values(SuperBlocks).indexOf(superBlock) + 1;
newMeta.superBlock = superBlock;
newMeta.challengeOrder = [[challengeId, 'Step 1']];
const newMetaDir = path.resolve(metaDir, block);
@ -190,10 +175,10 @@ This is a test for the new project-based curriculum.
}
async function createFirstChallenge(
superBlock: SuperBlock,
superBlock: SuperBlocks,
block: string
): Promise<string> {
const superBlockId = (superBlocks.indexOf(superBlock) + 1)
const superBlockId = (Object.values(SuperBlocks).indexOf(superBlock) + 1)
.toString()
.padStart(2, '0');
const newChallengeDir = path.resolve(
@ -234,9 +219,9 @@ prompt([
{
name: 'superBlock',
message: 'Which certification does this belong to?',
default: 'responsive-web-design',
default: SuperBlocks.RespWebDesign,
type: 'list',
choices: superBlocks
choices: SuperBlocks
},
{
name: 'block',

View File

@ -23,8 +23,6 @@
"create-project": "ts-node create-project"
},
"devDependencies": {
"@types/inquirer": "7.3.3",
"@types/node": "16.11.7",
"bson-objectid": "2.0.1",
"cross-env": "7.0.3",
"gray-matter": "4.0.3",

View File

@ -1,12 +0,0 @@
{
"compilerOptions": {
"target": "ES2020",
"noEmit": true,
"strict": true,
"moduleResolution": "node",
"esModuleInterop": true,
"resolveJsonModule": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true
}
}

View File

@ -1,9 +1,11 @@
const { spawn } = require('child_process');
const fs = require('fs');
const path = require('path');
import { spawn } from 'child_process';
import * as fs from 'fs';
import * as path from 'path';
const { availableLangs } = require('../../../config/i18n/all-langs');
const env = require('../../../config/read-env');
import { availableLangs } from '../../../config/i18n/all-langs';
// eslint-disable-next-line
const env = require('../../../config/read-env.js');
const globalConfigPath = path.resolve(__dirname, '../../../config');
@ -11,21 +13,25 @@ const { FREECODECAMP_NODE_ENV } = process.env;
function checkClientLocale() {
if (!availableLangs.client.includes(process.env.CLIENT_LOCALE)) {
/* eslint-disable @typescript-eslint/restrict-template-expressions */
throw Error(`
CLIENT_LOCALE, ${process.env.CLIENT_LOCALE}, is not an available language in config/i18n/all-langs.js
`);
/* eslint-enable @typescript-eslint/restrict-template-expressions */
}
}
function checkCurriculumLocale() {
if (!availableLangs.curriculum.includes(process.env.CURRICULUM_LOCALE)) {
/* eslint-disable @typescript-eslint/restrict-template-expressions */
throw Error(`
CURRICULUM_LOCALE, ${process.env.CURRICULUM_LOCALE}, is not an available language in config/i18n/all-langs.js
`);
/* eslint-enable @typescript-eslint/restrict-template-expressions */
}
}
@ -57,6 +63,7 @@ if (FREECODECAMP_NODE_ENV !== 'development') {
expectedVariables.sort();
receivedvariables.sort();
if (expectedVariables.length !== receivedvariables.length) {
/* eslint-disable @typescript-eslint/restrict-template-expressions */
throw Error(`
Env. variable validation failed. Make sure these keys are used and configured.
@ -71,9 +78,11 @@ if (FREECODECAMP_NODE_ENV !== 'development') {
)}
`);
/* eslint-enable @typescript-eslint/restrict-template-expressions */
}
for (const key of expectedVariables) {
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
if (typeof env[key] === 'undefined' || env[key] === null) {
throw Error(`
@ -86,16 +95,16 @@ if (FREECODECAMP_NODE_ENV !== 'development') {
if (env['environment'] !== 'production')
throw Error(`
Production environment should be 'production'
Production environment should be 'production'
`);
`);
if (env['showUpcomingChanges'])
throw Error(`
SHOW_UPCOMING_CHANGES should never be 'true' in production
SHOW_UPCOMING_CHANGES should never be 'true' in production
`);
`);
checkClientLocale();
checkCurriculumLocale();
@ -103,8 +112,10 @@ if (FREECODECAMP_NODE_ENV !== 'development') {
checkClientLocale();
checkCurriculumLocale();
if (fs.existsSync(`${globalConfigPath}/env.json`)) {
// eslint-disable-next-line
const { showUpcomingChanges } = require(`${globalConfigPath}/env.json`);
if (env['showUpcomingChanges'] !== showUpcomingChanges) {
/* eslint-enable @typescript-eslint/no-unsafe-member-access */
console.log(
'SHOW_UPCOMING_CHANGES value has changed, cleaning client cache.'
);

View File

@ -0,0 +1,6 @@
{
"compilerOptions": {
"typeRoots": ["../../node_modules/@types"],
"types": ["node"]
}
}

View File

@ -20,7 +20,6 @@
"homepage": "https://github.com/freeCodeCamp/freeCodeCamp#readme",
"dependencies": {
"@babel/preset-typescript": "7.16.0",
"@types/jest": "27.0.2",
"@types/node": "16.11.7",
"@types/react": "17.0.33",
"@types/react-dom": "17.0.11",
@ -39,18 +38,20 @@
"@storybook/addon-links": "6.3.12",
"@storybook/addon-postcss": "2.0.0",
"@storybook/react": "6.3.12",
"@testing-library/jest-dom": "^5.15.0",
"@testing-library/react": "12.1.2",
"@types/jest": "^27.0.2",
"autoprefixer": "10.4.0",
"babel-loader": "8.2.3",
"babel-plugin-transform-react-remove-prop-types": "0.4.24",
"cross-env": "7.0.3",
"postcss": "8.3.11",
"postcss-import": "14.0.2",
"tailwindcss": "2.2.19",
"rimraf": "3.0.2",
"rollup": "2.60.0",
"rollup-plugin-postcss": "4.0.1",
"rollup-plugin-terser": "7.0.2"
"rollup-plugin-terser": "7.0.2",
"tailwindcss": "2.2.19"
},
"scripts": {
"storybook": "start-storybook -p 6006",

View File

@ -8,6 +8,7 @@
"esModuleInterop": true,
"moduleResolution": "node",
"strict": true,
"noEmit": true
"noEmit": true,
"typeRoots": ["./node_modules/@types"]
}
}

View File

@ -1,5 +1,13 @@
{
"include": ["./i18n/**/*", "./plugins/**/*", "./src/**/*", "./utils/**/*"],
"include": [
"client/i18n/**/*",
"client/plugins/**/*",
"client/src/**/*",
"client/utils/**/*",
"tools/challenge-helper-scripts/**/*",
"config/certification-settings.ts",
"config/i18n/**/*"
],
"compilerOptions": {
"lib": ["WebWorker", "DOM", "DOM.Iterable"],
"target": "es2020",