From afabd4c964558bc42eab296f6d9028e6668295ad Mon Sep 17 00:00:00 2001 From: Mat Brown Date: Fri, 5 Jul 2019 20:38:43 -0400 Subject: [PATCH] Apply Prettier formatting rules to source code and remove unused disable directives --- .github/ISSUE_TEMPLATE/bug_report.md | 18 +- .github/ISSUE_TEMPLATE/feature_request.md | 1 - .stylelintrc.json | 54 +- .travis.yml | 130 ++-- CODE_OF_CONDUCT.md | 26 +- README.md | 155 ++-- TEST_PLAN.md | 54 +- __factories__/clients/firebase.js | 16 +- __mocks__/@firebase/app.js | 11 +- __mocks__/@firebase/auth.js | 1 - babel.config.js | 2 +- bower.json | 19 +- docker-compose.sync.yml | 6 +- docker-compose.yml | 4 +- gulpfile.js | 136 ++-- jest.config.js | 5 +- karma.conf.js | 2 +- src/actions/applicationLoaded.js | 4 +- src/actions/assignments.js | 11 +- src/actions/clients.js | 15 +- src/actions/compiledProjects.js | 7 +- src/actions/console.js | 18 +- src/actions/index.js | 12 +- src/actions/projects.js | 37 +- src/actions/ui.js | 55 +- src/actions/user.js | 15 +- src/clients/firebase.js | 103 +-- src/clients/github.js | 126 ++-- src/clients/googleAnalytics.js | 11 +- src/clients/googleClassroom.js | 4 +- src/clients/localStorage.js | 11 +- src/components/AccountMigration.jsx | 11 +- src/components/AccountMigrationComplete.jsx | 8 +- src/components/AccountMigrationError.jsx | 9 +- src/components/AccountMigrationInProgress.jsx | 6 +- .../AccountMigrationUndoGracePeriod.jsx | 8 +- src/components/AssignmentCreator.jsx | 34 +- src/components/AssignmentCreatorForm.jsx | 96 ++- .../AssignmentCreatorSelectField.jsx | 17 +- src/components/AssignmentCreatorTextField.jsx | 16 +- src/components/BrowserError.jsx | 4 +- src/components/CollapsedComponent.jsx | 18 +- src/components/Console.jsx | 39 +- src/components/ConsoleExpression.jsx | 10 +- src/components/ConsoleInput.jsx | 6 +- src/components/ConsoleOutput.jsx | 27 +- src/components/Editor.jsx | 17 +- src/components/EditorContainer.jsx | 53 +- src/components/EditorsColumn.jsx | 19 +- src/components/ErrorItem.jsx | 10 +- src/components/ErrorList.jsx | 21 +- src/components/ErrorReport.jsx | 21 +- src/components/Instructions.jsx | 28 +- src/components/Modal.jsx | 10 +- src/components/NotificationContainer.jsx | 15 +- src/components/NotificationList.jsx | 19 +- src/components/PopThrobber.jsx | 8 +- src/components/Preview.jsx | 11 +- src/components/PreviewFrame.jsx | 17 +- src/components/ProjectPreview.jsx | 44 +- src/components/ProposedAccountMigration.jsx | 19 +- src/components/TopBar/CurrentUserButton.jsx | 5 +- src/components/TopBar/CurrentUserMenu.jsx | 28 +- src/components/TopBar/ExportMenu.jsx | 8 +- src/components/TopBar/HamburgerMenu.jsx | 21 +- src/components/TopBar/HamburgerMenuButton.jsx | 4 +- src/components/TopBar/NewProjectButton.jsx | 5 +- src/components/TopBar/ProjectPicker.jsx | 26 +- src/components/TopBar/ProjectPickerButton.jsx | 17 +- src/components/TopBar/TextSize.jsx | 5 +- src/components/TopBar/createMenu.jsx | 35 +- src/components/TopBar/index.jsx | 6 +- src/components/Workspace.jsx | 161 ++-- .../GenericNotificationWithURL.jsx | 2 +- .../ProjectExportNotification.jsx | 6 +- .../notifications/SnapshotNotification.jsx | 18 +- src/config.js | 2 +- src/config/libraryAssets.js | 6 +- src/containers/AssignmentCreator.js | 27 +- src/containers/AssignmentCreatorForm.js | 3 +- src/containers/ErrorReport.js | 3 +- src/containers/Instructions.js | 5 +- src/containers/Preview.js | 6 +- src/containers/ProjectPreview.js | 5 +- src/containers/TopBar.js | 1 - src/containers/Workspace.js | 7 +- src/createApplicationStore.js | 5 +- src/css/application.css | 5 +- src/enums/index.js | 15 +- .../calculateFlexGrowAfterDrag.js | 8 +- .../resizableFlex/index.js | 98 ++- .../resizableFlex/sham.js | 6 +- src/html/index.html | 32 +- src/logic/__tests__/linkGithubIdentityTest.js | 16 +- .../__tests__/unlinkGithubIdentity.test.js | 7 +- src/logic/index.js | 5 +- src/logic/linkGithubIdentity.js | 5 +- src/patches/stylelint/lib/requireRule.js | 3 +- src/preview.js | 3 +- .../handleConsoleExpressions.js | 7 +- src/previewSupport/handleConsoleLogs.js | 2 +- src/previewSupport/overrideAlert.js | 2 +- src/records/AccountMigration.js | 13 +- src/records/CompiledProject.js | 13 +- src/records/ConsoleEntry.js | 15 +- src/records/ConsoleError.js | 11 +- src/records/ConsoleState.js | 15 +- src/records/Course.js | 17 +- src/records/EditorLocation.js | 13 +- src/records/Error.js | 23 +- src/records/ErrorList.js | 11 +- src/records/ErrorReport.js | 13 +- src/records/FormDate.js | 11 +- src/records/GoogleClassroom.js | 9 +- src/records/Notification.js | 13 +- src/records/RemoteCollection.js | 11 +- src/records/UiState.js | 29 +- src/records/User.js | 13 +- src/records/UserAccount.js | 15 +- src/records/UserIdentityProvider.js | 13 +- src/reducers/__tests__/console.test.jsx | 10 +- src/reducers/clients.js | 10 +- src/reducers/compiledProjects.js | 24 +- src/reducers/console.js | 139 ++-- src/reducers/errors.js | 30 +- src/reducers/googleClassroom.js | 21 +- src/reducers/index.js | 5 +- src/reducers/projects.js | 195 +++-- src/reducers/resizableFlex.js | 24 +- src/reducers/ui.js | 114 +-- src/reducers/user.js | 7 +- src/sagas/assignments.js | 45 +- src/sagas/clients.js | 26 +- src/sagas/compiledProjects.js | 17 +- src/sagas/errors.js | 22 +- src/sagas/manageUserState.js | 29 +- src/sagas/projects.js | 33 +- src/sagas/ui.js | 9 +- src/sagas/user.js | 19 +- src/selectors/getAllProjectKeys.js | 43 +- src/selectors/getAllProjects.js | 5 +- src/selectors/getCourse.js | 7 +- src/selectors/getCourses.js | 6 +- src/selectors/getCurrentCompiledProjectKey.js | 5 +- .../getCurrentProjectExportedRepoName.js | 8 +- .../getCurrentProjectPreviewTitle.js | 2 +- src/selectors/getCurrentValidationState.js | 2 +- src/selectors/getHiddenAndVisibleLanguages.js | 13 +- src/selectors/getParsedDate.js | 7 +- src/selectors/index.js | 9 +- src/selectors/isAssignmentCreatorOpen.js | 4 +- src/selectors/isAssignmentExportInProgress.js | 5 +- .../isCurrentProjectSyntacticallyValid.js | 5 +- src/selectors/isProjectExportInProgress.js | 7 +- .../isUserAuthenticatedWithGithub.js | 3 +- .../isUserAuthenticatedWithGoogle.js | 3 +- src/selectors/makeIsUserAuthenticatedWith.js | 20 +- src/services/gapi.js | 54 +- .../inlineStylePrefixer/prefixData.gen.js | 8 +- src/static/privacy.html | 88 ++- src/util/ExtendableError.js | 2 +- src/util/ace.js | 5 +- src/util/beautifySource.js | 11 +- src/util/compileProject.js | 36 +- src/util/errorUtils.js | 10 +- src/util/i18nFormatting.js | 5 +- src/util/javascript.js | 6 +- src/util/markdown.js | 11 +- src/util/normalizeError.js | 19 +- src/util/performWithRetries.js | 28 +- src/validations/Validator.js | 10 +- src/validations/css.js | 11 +- src/validations/css/css.js | 4 +- src/validations/css/prettycss.js | 17 +- src/validations/html.js | 13 +- src/validations/html/htmlInspector.js | 11 +- src/validations/html/htmllint.js | 15 +- src/validations/html/rules/MismatchedTag.js | 2 +- src/validations/html/rules/NodeOutsideBody.js | 24 +- src/validations/html/rules/index.js | 7 +- src/validations/html/runRules.js | 35 +- src/validations/html/slowparse.js | 6 +- src/validations/javascript.js | 9 +- src/validations/javascript/esprima.js | 11 +- src/validations/javascript/jshint.js | 14 +- src/validations/mergeValidations.js | 5 +- test/helpers/Scenario.js | 36 +- test/helpers/factory.js | 11 +- test/helpers/i18nFactory.js | 2 +- test/helpers/localizationTest.js | 22 +- test/helpers/reducerTest.js | 30 +- test/helpers/referenceStates.js | 44 +- test/helpers/testValidatorAcceptance.js | 7 +- test/helpers/validationTest.js | 7 +- test/unit/Analyzer.js | 6 +- .../calculateFlexGrowAfterDrag.js | 17 +- test/unit/localization/localization.js | 49 +- test/unit/reducers/clients.js | 140 ++-- test/unit/reducers/currentProject.js | 81 +- test/unit/reducers/errors.js | 145 ++-- test/unit/reducers/googleClassroom.js | 44 +- test/unit/reducers/projects.js | 587 +++++++------- test/unit/reducers/resizableFlex.js | 99 +-- test/unit/reducers/ui.js | 714 ++++++++++-------- test/unit/reducers/user.js | 261 ++++--- test/unit/sagas/assignments.js | 195 ++--- test/unit/sagas/clients.js | 224 +++--- test/unit/sagas/compiledProjects.js | 51 +- test/unit/sagas/errors.js | 106 +-- test/unit/sagas/manageUserState.js | 216 +++--- test/unit/sagas/projects.js | 345 +++++---- test/unit/sagas/ui.js | 99 ++- test/unit/sagas/user.js | 111 +-- test/unit/util/javascript.js | 26 +- test/unit/util/queryParams.js | 34 +- test/unit/validations/css.js | 244 +++--- test/unit/validations/html.js | 461 +++++------ test/unit/validations/html/rules.js | 86 +-- test/unit/validations/html/runRules.js | 269 ++++--- test/unit/validations/javascript.js | 92 ++- webpack.config.js | 60 +- 221 files changed, 4511 insertions(+), 4399 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/bug_report.md b/.github/ISSUE_TEMPLATE/bug_report.md index dd84ea7824..b5c68e55be 100644 --- a/.github/ISSUE_TEMPLATE/bug_report.md +++ b/.github/ISSUE_TEMPLATE/bug_report.md @@ -4,7 +4,6 @@ about: Create a report to help us improve title: '' labels: '' assignees: '' - --- **Describe the bug** @@ -12,6 +11,7 @@ A clear and concise description of what the bug is. **To Reproduce** Steps to reproduce the behavior: + 1. Go to '...' 2. Click on '....' 3. Scroll down to '....' @@ -24,15 +24,17 @@ A clear and concise description of what you expected to happen. If applicable, add screenshots to help explain your problem. **Desktop (please complete the following information):** - - OS: [e.g. iOS] - - Browser [e.g. chrome, safari] - - Version [e.g. 22] + +- OS: [e.g. iOS] +- Browser [e.g. chrome, safari] +- Version [e.g. 22] **Smartphone (please complete the following information):** - - Device: [e.g. iPhone6] - - OS: [e.g. iOS8.1] - - Browser [e.g. stock browser, safari] - - Version [e.g. 22] + +- Device: [e.g. iPhone6] +- OS: [e.g. iOS8.1] +- Browser [e.g. stock browser, safari] +- Version [e.g. 22] **Additional context** Add any other context about the problem here. diff --git a/.github/ISSUE_TEMPLATE/feature_request.md b/.github/ISSUE_TEMPLATE/feature_request.md index bbcbbe7d61..2f28cead03 100644 --- a/.github/ISSUE_TEMPLATE/feature_request.md +++ b/.github/ISSUE_TEMPLATE/feature_request.md @@ -4,7 +4,6 @@ about: Suggest an idea for this project title: '' labels: '' assignees: '' - --- **Is your feature request related to a problem? Please describe.** diff --git a/.stylelintrc.json b/.stylelintrc.json index 1c778a2eec..8603329541 100644 --- a/.stylelintrc.json +++ b/.stylelintrc.json @@ -6,40 +6,40 @@ "block-no-empty": true, "color-hex-length": "short", "color-no-invalid-hex": true, - "comment-empty-line-before": ["always", { - "except": ["first-nested"], - "ignore": ["stylelint-commands"] - }], + "comment-empty-line-before": [ + "always", + { + "except": ["first-nested"], + "ignore": ["stylelint-commands"] + } + ], "comment-no-empty": true, "comment-whitespace-inside": "always", - "custom-property-empty-line-before": ["always", { - "except": [ - "after-custom-property", - "first-nested" - ], - "ignore": [ - "after-comment", - "inside-single-line-block" - ] - }], + "custom-property-empty-line-before": [ + "always", + { + "except": ["after-custom-property", "first-nested"], + "ignore": ["after-comment", "inside-single-line-block"] + } + ], "declaration-bang-space-after": "never", "declaration-bang-space-before": "always", - "declaration-block-no-duplicate-properties": [true, { - "ignore": ["consecutive-duplicates-with-different-values"] - }], + "declaration-block-no-duplicate-properties": [ + true, + { + "ignore": ["consecutive-duplicates-with-different-values"] + } + ], "declaration-block-no-redundant-longhand-properties": true, "declaration-block-no-shorthand-property-overrides": true, "declaration-block-single-line-max-declarations": 1, - "declaration-empty-line-before": ["always", { - "except": [ - "after-declaration", - "first-nested" - ], - "ignore": [ - "after-comment", - "inside-single-line-block" - ] - }], + "declaration-empty-line-before": [ + "always", + { + "except": ["after-declaration", "first-nested"], + "ignore": ["after-comment", "inside-single-line-block"] + } + ], "font-family-no-duplicate-names": true, "function-calc-no-unspaced-operator": true, "function-linear-gradient-no-nonstandard-direction": true, diff --git a/.travis.yml b/.travis.yml index fc3e00da0c..0802bf31f8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,77 +3,77 @@ branches: - master language: minimal services: -- docker + - docker install: -- docker pull popcodeorg/popcode:latest -- docker build --pull --cache-from popcodeorg/popcode:latest --tag popcode . + - docker pull popcodeorg/popcode:latest + - docker build --pull --cache-from popcodeorg/popcode:latest --tag popcode . script: -- docker run --env NODE_ENV=test popcode yarn test -- >- - docker run - --env NODE_ENV=production - --env FIREBASE_APP - --env FIREBASE_API_KEY - --env FIREBASE_CLIENT_ID - --env GIT_REVISION="$TRAVIS_COMMIT" - --env GOOGLE_ANALYTICS_TRACKING_ID - --volume="$TRAVIS_BUILD_DIR/dist:/app/dist" - popcode - yarn run gulp build -- >- - docker run - --volume=$TRAVIS_BUILD_DIR/dist:/app/dist - popcode - yarn run eslint --no-eslintrc --env es5 dist + - docker run --env NODE_ENV=test popcode yarn test + - >- + docker run + --env NODE_ENV=production + --env FIREBASE_APP + --env FIREBASE_API_KEY + --env FIREBASE_CLIENT_ID + --env GIT_REVISION="$TRAVIS_COMMIT" + --env GOOGLE_ANALYTICS_TRACKING_ID + --volume="$TRAVIS_BUILD_DIR/dist:/app/dist" + popcode + yarn run gulp build + - >- + docker run + --volume=$TRAVIS_BUILD_DIR/dist:/app/dist + popcode + yarn run eslint --no-eslintrc --env es5 dist before_deploy: -- >- - docker run - --env FIREBASE_APP - --env FIREBASE_SECRET - popcode - yarn run gulp syncFirebase + - >- + docker run + --env FIREBASE_APP + --env FIREBASE_SECRET + popcode + yarn run gulp syncFirebase deploy: -- provider: s3 - access_key_id: AKIAJY2GYDQBE4HFF32Q - secret_access_key: - secure: qqkSdpnlOM80HavspUc/S4OpohDAkbDqaCKQTw08j2/CaU0LwN335CVQhDZ4Oskgr6y5evx6LrTU0BNiDfzcMIEykokV1ZCPLuWLrHo/ZtCSIU+3ikVErY/0qZH4FdZ1h/Q1FP5gTDydP0QbXWkQsQQg1cgg2NTX4/BsTTT9nBRJeg4Gdm9ARLW0b3SGutW13tW8fuRG9YrNJs6gKZsZ6FhP1ru4T47tdsbphV1IsedZv8nU7dGnWQj67//4OpAHOi1KOm6K1CprNa35Kw7D/+n6786skbPi7Tsu7UbIVMWD+Jy1c2xtz3mqinIbyS8spzLd3kbDV+BRvIYXXHpC6B4gGhyRd+ohN+WcoDQZJha2PaOfIPfAxPhK2IKO6h+6i8Q0CK4/x4Yd8PurVHrB8KEyPrMHPa42abMTTeRLs7OAjrtM7dWucngCvW6fBqhpgp36cRDZeXLKjywkapo1/6l64fjkM+wGkYFkI5i6qzEAr0JvBrIeTDiymz1Oitf3Uio+vs4hfjXegQansq5l/mXtMdI9DfNrKm/R2zpUp1qS7i+v1MfnhAxd8NOEGYpT75sJbSVca0jgnkLXcja6+O4oRswx4maA+BTiIcwknAn6B4Rupf8U0Tnt3s/pFu6Ih6lnMo6rpeBkV7FO1Bwyv59zyxZS8Z23ec+v7+TZ/iE= - bucket: popcode.org - skip_cleanup: true - local-dir: dist - acl: public_read - on: - repo: popcodeorg/popcode - branch: master -- provider: s3 - access_key_id: AKIAJY2GYDQBE4HFF32Q - secret_access_key: - secure: qqkSdpnlOM80HavspUc/S4OpohDAkbDqaCKQTw08j2/CaU0LwN335CVQhDZ4Oskgr6y5evx6LrTU0BNiDfzcMIEykokV1ZCPLuWLrHo/ZtCSIU+3ikVErY/0qZH4FdZ1h/Q1FP5gTDydP0QbXWkQsQQg1cgg2NTX4/BsTTT9nBRJeg4Gdm9ARLW0b3SGutW13tW8fuRG9YrNJs6gKZsZ6FhP1ru4T47tdsbphV1IsedZv8nU7dGnWQj67//4OpAHOi1KOm6K1CprNa35Kw7D/+n6786skbPi7Tsu7UbIVMWD+Jy1c2xtz3mqinIbyS8spzLd3kbDV+BRvIYXXHpC6B4gGhyRd+ohN+WcoDQZJha2PaOfIPfAxPhK2IKO6h+6i8Q0CK4/x4Yd8PurVHrB8KEyPrMHPa42abMTTeRLs7OAjrtM7dWucngCvW6fBqhpgp36cRDZeXLKjywkapo1/6l64fjkM+wGkYFkI5i6qzEAr0JvBrIeTDiymz1Oitf3Uio+vs4hfjXegQansq5l/mXtMdI9DfNrKm/R2zpUp1qS7i+v1MfnhAxd8NOEGYpT75sJbSVca0jgnkLXcja6+O4oRswx4maA+BTiIcwknAn6B4Rupf8U0Tnt3s/pFu6Ih6lnMo6rpeBkV7FO1Bwyv59zyxZS8Z23ec+v7+TZ/iE= - bucket: popcode.school - skip_cleanup: true - local-dir: dist - acl: public_read - on: - repo: popcodeorg/popcode - branch: master -- provider: script - script: >- - echo "$DOCKER_PASSWORD" | - docker login -u "$DOCKER_USERNAME" --password-stdin && - docker tag popcode popcodeorg/popcode && - docker push popcodeorg/popcode - on: - repo: popcodeorg/popcode - branch: master + - provider: s3 + access_key_id: AKIAJY2GYDQBE4HFF32Q + secret_access_key: + secure: qqkSdpnlOM80HavspUc/S4OpohDAkbDqaCKQTw08j2/CaU0LwN335CVQhDZ4Oskgr6y5evx6LrTU0BNiDfzcMIEykokV1ZCPLuWLrHo/ZtCSIU+3ikVErY/0qZH4FdZ1h/Q1FP5gTDydP0QbXWkQsQQg1cgg2NTX4/BsTTT9nBRJeg4Gdm9ARLW0b3SGutW13tW8fuRG9YrNJs6gKZsZ6FhP1ru4T47tdsbphV1IsedZv8nU7dGnWQj67//4OpAHOi1KOm6K1CprNa35Kw7D/+n6786skbPi7Tsu7UbIVMWD+Jy1c2xtz3mqinIbyS8spzLd3kbDV+BRvIYXXHpC6B4gGhyRd+ohN+WcoDQZJha2PaOfIPfAxPhK2IKO6h+6i8Q0CK4/x4Yd8PurVHrB8KEyPrMHPa42abMTTeRLs7OAjrtM7dWucngCvW6fBqhpgp36cRDZeXLKjywkapo1/6l64fjkM+wGkYFkI5i6qzEAr0JvBrIeTDiymz1Oitf3Uio+vs4hfjXegQansq5l/mXtMdI9DfNrKm/R2zpUp1qS7i+v1MfnhAxd8NOEGYpT75sJbSVca0jgnkLXcja6+O4oRswx4maA+BTiIcwknAn6B4Rupf8U0Tnt3s/pFu6Ih6lnMo6rpeBkV7FO1Bwyv59zyxZS8Z23ec+v7+TZ/iE= + bucket: popcode.org + skip_cleanup: true + local-dir: dist + acl: public_read + on: + repo: popcodeorg/popcode + branch: master + - provider: s3 + access_key_id: AKIAJY2GYDQBE4HFF32Q + secret_access_key: + secure: qqkSdpnlOM80HavspUc/S4OpohDAkbDqaCKQTw08j2/CaU0LwN335CVQhDZ4Oskgr6y5evx6LrTU0BNiDfzcMIEykokV1ZCPLuWLrHo/ZtCSIU+3ikVErY/0qZH4FdZ1h/Q1FP5gTDydP0QbXWkQsQQg1cgg2NTX4/BsTTT9nBRJeg4Gdm9ARLW0b3SGutW13tW8fuRG9YrNJs6gKZsZ6FhP1ru4T47tdsbphV1IsedZv8nU7dGnWQj67//4OpAHOi1KOm6K1CprNa35Kw7D/+n6786skbPi7Tsu7UbIVMWD+Jy1c2xtz3mqinIbyS8spzLd3kbDV+BRvIYXXHpC6B4gGhyRd+ohN+WcoDQZJha2PaOfIPfAxPhK2IKO6h+6i8Q0CK4/x4Yd8PurVHrB8KEyPrMHPa42abMTTeRLs7OAjrtM7dWucngCvW6fBqhpgp36cRDZeXLKjywkapo1/6l64fjkM+wGkYFkI5i6qzEAr0JvBrIeTDiymz1Oitf3Uio+vs4hfjXegQansq5l/mXtMdI9DfNrKm/R2zpUp1qS7i+v1MfnhAxd8NOEGYpT75sJbSVca0jgnkLXcja6+O4oRswx4maA+BTiIcwknAn6B4Rupf8U0Tnt3s/pFu6Ih6lnMo6rpeBkV7FO1Bwyv59zyxZS8Z23ec+v7+TZ/iE= + bucket: popcode.school + skip_cleanup: true + local-dir: dist + acl: public_read + on: + repo: popcodeorg/popcode + branch: master + - provider: script + script: >- + echo "$DOCKER_PASSWORD" | + docker login -u "$DOCKER_USERNAME" --password-stdin && + docker tag popcode popcodeorg/popcode && + docker push popcodeorg/popcode + on: + repo: popcodeorg/popcode + branch: master after_deploy: -- > - docker run - --env CLOUDFLARE_EMAIL - --env CLOUDFLARE_KEY - --env CLOUDFLARE_ZONE - --env HOSTNAME - popcode - yarn run gulp purgeCache + - > + docker run + --env CLOUDFLARE_EMAIL + --env CLOUDFLARE_KEY + --env CLOUDFLARE_ZONE + --env HOSTNAME + popcode + yarn run gulp purgeCache notifications: slack: secure: IJ0LSnahbfPFMFFgEK+wwSYEUWjJ2AFZz89oSmzSuKqEchM7AA2tpkCAPvN37cUksPE4YozVXxx++SQ4j+fk1lmhhddEUYO9ueB/UqD3iu0xCFR/CJ30ka7QDkfzkatKkn0H8MVU3FwEJ6ZbHJR2zJVUALPFw7AQ08EE4GpTC2TfWSiYuv1AnuVUC8ZkvGBjwFN1lQrAnHFS62sreNmYtBR0FHHo9DEE+NanYdtLnFYyGeDauWx7I1ERT1vnv4G+0vx5Guu7TGwC1uzHCTlciqSGPeaifaC+uXR/8VaTabZS4G1PsR8ROYt3S/RFtCEAfuhBvlcWdNnfLH7/xLhET4W35H/hhHmSaMYJCy/gnQW/bXfLCxtO5/luwM5nOM4NeQcRybqreBL/q4K78giw6ttpTo5EumBxXrYKo4PRWfOWkOhePotQ/IRzpsoMqFHxzlJxv9HPSnFb+11OTe3BsxfWpsHs233eIBpKYOcjpzXPP4GSq7FH2V7jL2lg6Cc81XUK2v8upJpPoWRRfM52LxemNi+uEMBrgLro6VA2O5qRDN/+mhr8wYS4dLms5uk6Hq87UA9xhlIUl0P9d6kfN0vHi+QzxLMLvA1ateFncaG7MKTgMNjsckziKlR2B8FZ1c3lT55RB/zfojGzrDs0l7TCKB+WKP5uPJEWw5/UC2A= diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index cc91072bef..4e8b389bcb 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -14,22 +14,22 @@ appearance, race, religion, or sexual identity and orientation. Examples of behavior that contributes to creating a positive environment include: -* Using welcoming and inclusive language -* Being respectful of differing viewpoints and experiences -* Gracefully accepting constructive criticism -* Focusing on what is best for the community -* Showing empathy towards other community members +- Using welcoming and inclusive language +- Being respectful of differing viewpoints and experiences +- Gracefully accepting constructive criticism +- Focusing on what is best for the community +- Showing empathy towards other community members Examples of unacceptable behavior by participants include: -* The use of sexualized language or imagery and unwelcome sexual attention or - advances -* Trolling, insulting/derogatory comments, and personal or political attacks -* Public or private harassment -* Publishing others' private information, such as a physical or electronic - address, without explicit permission -* Other conduct which could reasonably be considered inappropriate in a - professional setting +- The use of sexualized language or imagery and unwelcome sexual attention or + advances +- Trolling, insulting/derogatory comments, and personal or political attacks +- Public or private harassment +- Publishing others' private information, such as a physical or electronic + address, without explicit permission +- Other conduct which could reasonably be considered inappropriate in a + professional setting ## Our Responsibilities diff --git a/README.md b/README.md index 3397b96b73..91bf1bc7ee 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Popcode # +# Popcode [Popcode](https://popcode.org) is a simple HTML/CSS/JavaScript editing environment for use in the classroom. It's a lot like [JSBin](http://jsbin.com), @@ -7,20 +7,21 @@ giving specific, immediate, human-friendly feedback when the code contains error [![](https://user-images.githubusercontent.com/11786205/47052459-6673a080-d176-11e8-9c1b-b433a2af7c72.jpg)](https://popcode.org) -### Project status ### +### Project status [![Build Status](https://travis-ci.org/popcodeorg/popcode.svg?branch=master)](https://travis-ci.org/popcodeorg/popcode) [![Dependency Status](https://david-dm.org/popcodeorg/popcode.svg)](https://david-dm.org/popcodeorg/popcode) ![License](https://img.shields.io/github/license/popcodeorg/popcode.svg) Popcode is the official first semester editing environment for the [ScriptEd program](https://scripted.org) in the 2018–2019 school year. -### Try it out ### +### Try it out You can try out Popcode at [`https://popcode.org`](https://popcode.org). + ## Table of Contents - [Features](#features) @@ -39,23 +40,23 @@ You can try out Popcode at -## Features ## +## Features -* Edit HTML, CSS, and JavaScript in the browser; in-browser preview updates as +- Edit HTML, CSS, and JavaScript in the browser; in-browser preview updates as you type. -* Get immediate, comprehensive, easy-to-understand feedback about problems in +- Get immediate, comprehensive, easy-to-understand feedback about problems in your code. -* Errors can't be ignored. If there are any errors in the code, the live +- Errors can't be ignored. If there are any errors in the code, the live preview is replaced by an error list. -* JavaScript runtime errors are also reported in human-friendly language, with +- JavaScript runtime errors are also reported in human-friendly language, with annotations in the source code pointing out the source of the problem. -* One-click login using GitHub account; all work is saved remotely to +- One-click login using GitHub account; all work is saved remotely to [Firebase](https://firebase.google.com/) when logged in. -* Pop out preview of web page in its own window. -* Export to GitHub gist. -* Import starter code from a GitHub gist. +- Pop out preview of web page in its own window. +- Export to GitHub gist. +- Import starter code from a GitHub gist. -### About validation ### +### About validation The validation system is the main point of this project. Most syntax checkers, linters, and style enforcers tend to provide feedback using language that is @@ -68,11 +69,11 @@ enforced style decisions are arbitrary, under the philosophy that giving students one right way to do it eliminates ambiguity and aids the learning process. -### Feature roadmap ### +### Feature roadmap Check out the [Project Board](https://github.com/popcodeorg/popcode/projects/3). -## Technical details ## +## Technical details Popcode uses [**React**](https://facebook.github.io/react/) to render views, [**Redux**](http://redux.js.org/) to manage application state, @@ -89,29 +90,29 @@ Popcode detects code errors using [stylelint](https://github.com/stylelint/stylelint), [jshint](https://github.com/jshint/jshint), and [esprima](http://esprima.org/). -### Architecture Overview ### +### Architecture Overview The architecture of Popcode’s code base is best understood through the lifecycle of a user interaction: -* User interactions are first captured by handlers in React +- User interactions are first captured by handlers in React [components](https://github.com/popcodeorg/popcode/tree/master/src/components). -* These components propagate the event to the view controller, the [`Workspace` +- These components propagate the event to the view controller, the [`Workspace` component](https://github.com/popcodeorg/popcode/blob/master/src/components/Workspace.jsx). -* The `Workspace` dispatches one or more Redux +- The `Workspace` dispatches one or more Redux [actions](https://github.com/popcodeorg/popcode/tree/master/src/actions). -* Dispatched actions are consumed by the +- Dispatched actions are consumed by the [reducers](https://github.com/popcodeorg/popcode/tree/master/src/reducers), which update the [store](https://github.com/popcodeorg/popcode/blob/master/src/store.js). -* Action creators also perform other business logic, such as initiating +- Action creators also perform other business logic, such as initiating [validation](https://github.com/popcodeorg/popcode/tree/master/src/validations) of project code and persisting changes to [persistent storage](https://github.com/popcodeorg/popcode/blob/master/src/persistors). -* When the action lifecycle is complete, the `Workspace` receives updated +- When the action lifecycle is complete, the `Workspace` receives updated props from the store and propagates them to its descendants. -## Contributing ## +## Contributing Yes please! There are a [ton of ways](https://github.com/popcodeorg/popcode/issues) @@ -130,7 +131,7 @@ which lists the features and enhancements that the ScriptEd PMs have identified as most beneficial based on observation of hundreds of student users and feedback from dozens of instructors. -### Running locally ### +### Running locally Make sure you have a local installation of [Node.js](https://nodejs.org/en/download/) and [yarn](https://yarnpkg.com/lang/en/docs/install/). @@ -156,9 +157,9 @@ When you're done, lint and make sure tests pass before opening a pull request: $ yarn test ``` -### Debug Mode ### +### Debug Mode -By default, Popcode’s JavaScript code is compiled to ES5 to support a wide +By default, Popcode’s JavaScript code is compiled to ES5 to support a wide array of older browsers. This can make it difficult to debug errors, however, as the compiled code in the debugger can look quite different from the original source code. @@ -183,75 +184,75 @@ $ docker pull popcodeorg/popcode:latest # Not required, but will speed up instal $ docker-compose up ``` -### Developer Reference ### +### Developer Reference Popcode endeavors to use up-to-date technologies and code conventions to make development as pleasant as possible. Below are links to reference documentation on the major tools: -* [React](https://facebook.github.io/react/docs/react-component.html) for +- [React](https://facebook.github.io/react/docs/react-component.html) for constructing the user interface -* [Redux](http://redux.js.org/) for managing application state -* [postcss-preset-env](https://github.com/csstools/postcss-preset-env) gives us cutting-edge CSS features -* [Block Element Modifier](https://en.bem.info/methodology/naming-convention/) +- [Redux](http://redux.js.org/) for managing application state +- [postcss-preset-env](https://github.com/csstools/postcss-preset-env) gives us cutting-edge CSS features +- [Block Element Modifier](https://en.bem.info/methodology/naming-convention/) provides a convention for organizing DOM classes -* [Webpack](https://webpack.github.io/docs/configuration.html) builds the +- [Webpack](https://webpack.github.io/docs/configuration.html) builds the JavaScript -* [Tape](https://github.com/substack/tape) provides the test harness +- [Tape](https://github.com/substack/tape) provides the test harness -## License ## +## License Popcode is distributed under the MIT license. See the attached LICENSE file for all the sordid details. -## Contributors ## - -* [Mat Brown](https://github.com/outoftime) (maintainer) -* [Alejandro AR](https://github.com/kinduff) -* [Vaibhav Verma](https://github.com/v) -* [Alex Pelan](https://github.com/alexpelan) -* [Carol Chau](https://github.com/carolchau) -* [Jesse Wang](https://github.com/jwang1919) -* [Eric Lewis](http://www.ericandrewlewis.com/) -* [Razzi Abuissa](https://razzi.abuissa.net/) -* [Jeremy Schrader](http://www.pattern-factory.com/) -* [Leo McLay](https://github.com/leo-alexander) -* [Frederic Brodbeck](http://www.freder.io/) -* [Ben Yelsey](https://github.com/inlinestyle) -* [Aaron Greenberg](https://github.com/ajgreenb) -* [Peter Jablonski](https://github.com/pwjablonski) -* [Ten-Young Guh](https://github.com/tenyoung795) -* [Ilona Brand](https://github.com/ibrand) -* [Kaylee Knowles](https://github.com/kaylee42) -* [Felicia Wong](https://github.com/quixotically) -* [Tim Miller](https://github.com/gangstertim) -* [Bruno Garcia](http://twitter.com/b_garcia) -* [Cory Etzkorn](http://www.coryetzkorn.com/) -* [Nick Volpe](https://github.com/iamnickvolpe) -* [Craig Iturbe](https://github.com/citurbe) -* [Wylie Conlon](http://wylie.su/) -* [Gary Pang](http://www.codewritingcow.com/) -* [Alessia Bellisario](http://aless.co/) -* [Roan Kattouw](https://github.com/catrope) -* [Harpreet Singh](https://github.com/harry1064) -* [Limon Monte](https://limonte.github.io/) -* [Matthew Armstrong](https://github.com/raingerber) -* [Matt Garbis](http://www.mattgarbis.com/) -* [Ilya Gribov](https://github.com/igrib) -* [Chase Starr](http://www.twitter.com/captivechains) -* [Alec Merdler](https://github.com/alecmerdler) -* [Eric Snell](http://ericsnell.github.io/portfolio) -* [Omar De Leo](https://github.com/omardeleo) -* [Katie Conneally](http://www.katieconneally.com/) created the name Popcode -* Logo design, "Pop" concept, and branding elements by the team at +## Contributors + +- [Mat Brown](https://github.com/outoftime) (maintainer) +- [Alejandro AR](https://github.com/kinduff) +- [Vaibhav Verma](https://github.com/v) +- [Alex Pelan](https://github.com/alexpelan) +- [Carol Chau](https://github.com/carolchau) +- [Jesse Wang](https://github.com/jwang1919) +- [Eric Lewis](http://www.ericandrewlewis.com/) +- [Razzi Abuissa](https://razzi.abuissa.net/) +- [Jeremy Schrader](http://www.pattern-factory.com/) +- [Leo McLay](https://github.com/leo-alexander) +- [Frederic Brodbeck](http://www.freder.io/) +- [Ben Yelsey](https://github.com/inlinestyle) +- [Aaron Greenberg](https://github.com/ajgreenb) +- [Peter Jablonski](https://github.com/pwjablonski) +- [Ten-Young Guh](https://github.com/tenyoung795) +- [Ilona Brand](https://github.com/ibrand) +- [Kaylee Knowles](https://github.com/kaylee42) +- [Felicia Wong](https://github.com/quixotically) +- [Tim Miller](https://github.com/gangstertim) +- [Bruno Garcia](http://twitter.com/b_garcia) +- [Cory Etzkorn](http://www.coryetzkorn.com/) +- [Nick Volpe](https://github.com/iamnickvolpe) +- [Craig Iturbe](https://github.com/citurbe) +- [Wylie Conlon](http://wylie.su/) +- [Gary Pang](http://www.codewritingcow.com/) +- [Alessia Bellisario](http://aless.co/) +- [Roan Kattouw](https://github.com/catrope) +- [Harpreet Singh](https://github.com/harry1064) +- [Limon Monte](https://limonte.github.io/) +- [Matthew Armstrong](https://github.com/raingerber) +- [Matt Garbis](http://www.mattgarbis.com/) +- [Ilya Gribov](https://github.com/igrib) +- [Chase Starr](http://www.twitter.com/captivechains) +- [Alec Merdler](https://github.com/alecmerdler) +- [Eric Snell](http://ericsnell.github.io/portfolio) +- [Omar De Leo](https://github.com/omardeleo) +- [Katie Conneally](http://www.katieconneally.com/) created the name Popcode +- Logo design, "Pop" concept, and branding elements by the team at [Red Peak](http://redpeakgroup.com): Andrew Haug, Aya Kawabata, Jieun Lee, Achu Fones, Iwona Waluk, Stewart Devlin, and Katie Conneally -* User interface designed by [Ariel Liu](https://github.com/charstarstars), +- User interface designed by [Ariel Liu](https://github.com/charstarstars), [Ian Jones](https://github.com/ianmclaury), [Meghan Knoll](https://github.com/megknoll), and [Simon Lesser](https://twitter.com/simonlesser). -## Thanks to ## +## Thanks to These companies generously offer Popcode access to paid tiers of their excellent services, free of charge: @@ -273,7 +274,7 @@ src="https://cloud.githubusercontent.com/assets/14214/19059115/428a80f4-89ab-11e -## Contact ## +## Contact Feel free to email me at [mat.a.brown@gmail.com](mailto:mat.a.brown@gmail.com) if you have any questions. diff --git a/TEST_PLAN.md b/TEST_PLAN.md index 02432b5fc1..acf01082bd 100644 --- a/TEST_PLAN.md +++ b/TEST_PLAN.md @@ -13,75 +13,75 @@ parts that seem relevant to your code changes. ### Basic functionality -* [Load the application](http://localhost:3000). Ensure that the environment +- [Load the application](http://localhost:3000). Ensure that the environment loads without errors. -* Add some content to the HTML and make sure the preview renders correctly. Add +- Add some content to the HTML and make sure the preview renders correctly. Add some styles and make sure those are applied. -* Add some invalid CSS. Make sure that the appropriate error messages appear in +- Add some invalid CSS. Make sure that the appropriate error messages appear in the output column and as annotations in the source. Make sure that clicking the message in the error list focuses the cursor on the location in the source. -* Click the pop-out button. Ensure that a new tab opens with the rendered page. -* Minimize various editors by clicking the appropriate label. Maximize them by +- Click the pop-out button. Ensure that a new tab opens with the rendered page. +- Minimize various editors by clicking the appropriate label. Maximize them by clicking the bar at the bottom of the editors column. -* Click the zoom in button. Ensure that the text in the editors gets bigger. +- Click the zoom in button. Ensure that the text in the editors gets bigger. Click it again and ensure that the text returns to normal size. ### Persistence -* Log out if you are logged in. -* Add some content to the HTML. -* Refresh the browser tab. Verify that your content is still there. -* Close the browser tab, then open Popcode in a new tab. Verify that your +- Log out if you are logged in. +- Add some content to the HTML. +- Refresh the browser tab. Verify that your content is still there. +- Close the browser tab, then open Popcode in a new tab. Verify that your content is still there. -* Without closing the current tab, open another Popcode instance in a new tab. +- Without closing the current tab, open another Popcode instance in a new tab. Verify that the environment contains a fresh project. ### Libraries -* Type some JavaScript that requires jQuery. Ensure that an error message +- Type some JavaScript that requires jQuery. Ensure that an error message appears suggesting you enable jQuery. -* Enable jQuery and ensure that the page now renders and behaves as expected. +- Enable jQuery and ensure that the page now renders and behaves as expected. The menu should stay visible after you select jQuery. ### Snapshots -* Add some content to the page. Click **Snapshot**. Click the prompt to +- Add some content to the page. Click **Snapshot**. Click the prompt to copy. -* Paste the URL from your clipboard into a new tab. Verify that the project +- Paste the URL from your clipboard into a new tab. Verify that the project contains the content that you exported. ### Gist import & project instructions -* Open [a gist import +- Open [a gist import URL](http://localhost:3000/?gist=339c841617fb50c98420d9f37654039d) and ensure that the gist is imported into the environment -* Open [a gist with +- Open [a gist with instructions](http://localhost:3000/?gist=911a82a17a280545858d2d8ecc557ef3). Verify that the instructions appear in the left pane of the environment. -* Click the dark gray bar to the right of the instructions. Ensure that the +- Click the dark gray bar to the right of the instructions. Ensure that the instructions are hidden. -* Click it again. Ensure that the instructions are visible. +- Click it again. Ensure that the instructions are visible. ### Login -* Open a fresh Popcode environment, and log in. Verify that current project is +- Open a fresh Popcode environment, and log in. Verify that current project is still a new, blank template. -* Open a fresh Popcode environment, and add something to the HTML. Then log in. +- Open a fresh Popcode environment, and add something to the HTML. Then log in. Verify that the code you were just working on is still on screen. -* Open a second Popcode tab. Verify that you are are logged in, and looking at +- Open a second Popcode tab. Verify that you are are logged in, and looking at a fresh project. -* Modify the project, and then log out. Verify that you are logged out in both +- Modify the project, and then log out. Verify that you are logged out in both tabs, and both tabs still have the same project as before. -* Log back in. Create a new project. Verify that the code on screen is now the +- Log back in. Create a new project. Verify that the code on screen is now the defaults. -* Click on “Load Project”, and verify that you can go back to the project you +- Click on “Load Project”, and verify that you can go back to the project you were working on before you clicked “New Project” ### Gist export -* Export a gist while logged out. Verify that the contents of the gist match +- Export a gist while logged out. Verify that the contents of the gist match what was in your Popcode environment. -* Export a gist while logged in. Verify that the gist is associated with your +- Export a gist while logged in. Verify that the gist is associated with your GitHub account, and that it contains a link to re-import the gist into Popcode. diff --git a/__factories__/clients/firebase.js b/__factories__/clients/firebase.js index ee84d979ab..ca939da8c8 100644 --- a/__factories__/clients/firebase.js +++ b/__factories__/clients/firebase.js @@ -21,12 +21,12 @@ export const firebaseErrorFactory = Factory.define( name: 'some other error', }); -export const credentialInUseErrorFactory = new Factory().extend( - firebaseErrorFactory, -).attrs({ - name: 'auth/credential-already-in-use', - credential: () => credentialFactory.build(), -}); +export const credentialInUseErrorFactory = new Factory() + .extend(firebaseErrorFactory) + .attrs({ + name: 'auth/credential-already-in-use', + credential: () => credentialFactory.build(), + }); export const userProviderDataFactory = new Factory().attrs({ displayName: 'popcoder', @@ -37,9 +37,7 @@ export const userProviderDataFactory = new Factory().attrs({ uid: '1234567', }); -export const userFactory = new Factory().extend( - userProviderDataFactory, -).attrs({ +export const userFactory = new Factory().extend(userProviderDataFactory).attrs({ emailVerified: false, isAnonymous: false, metadata: { diff --git a/__mocks__/@firebase/app.js b/__mocks__/@firebase/app.js index 8ae1bf721f..c1967a7dac 100644 --- a/__mocks__/@firebase/app.js +++ b/__mocks__/@firebase/app.js @@ -5,13 +5,10 @@ class AuthProvider { } export const firebase = { - auth: Object.assign( - () => ({}), - { - GithubAuthProvider: AuthProvider, - GoogleAuthProvider: AuthProvider, - }, - ), + auth: Object.assign(() => ({}), { + GithubAuthProvider: AuthProvider, + GoogleAuthProvider: AuthProvider, + }), initializeApp: constant({}), }; diff --git a/__mocks__/@firebase/auth.js b/__mocks__/@firebase/auth.js index 5ecd74a64a..ff8b4c5632 100644 --- a/__mocks__/@firebase/auth.js +++ b/__mocks__/@firebase/auth.js @@ -1,2 +1 @@ -/* eslint-disable import/no-anonymous-default-export */ export default {}; diff --git a/babel.config.js b/babel.config.js index 9116ec2af5..cfe013eb36 100644 --- a/babel.config.js +++ b/babel.config.js @@ -1,7 +1,7 @@ const fs = require('fs'); const path = require('path'); -module.exports = (api) => { +module.exports = api => { let targets; const isJest = api.caller(({name}) => name === 'babel-jest'); diff --git a/bower.json b/bower.json index 124ee4b733..88238742ec 100644 --- a/bower.json +++ b/bower.json @@ -2,25 +2,12 @@ "name": "popcode", "description": "Web-based HTML/CSS/JS editor for educational use", "main": "src/application.js", - "authors": [ - "Mat Brown" - ], + "authors": ["Mat Brown"], "license": "MIT", - "keywords": [ - "code", - "editor", - "education", - "learning" - ], + "keywords": ["code", "editor", "education", "learning"], "homepage": "https://github.com/popcodeorg/popcode", "private": true, - "ignore": [ - "**/.*", - "node_modules", - "bower_components", - "test", - "tests" - ], + "ignore": ["**/.*", "node_modules", "bower_components", "test", "tests"], "dependencies": { "bootstrap": "^3.3.6", "lodash": "^4.11.2", diff --git a/docker-compose.sync.yml b/docker-compose.sync.yml index e3f45d9148..cce44a1cc2 100644 --- a/docker-compose.sync.yml +++ b/docker-compose.sync.yml @@ -29,6 +29,6 @@ services: environment: [] volumes: - ? app-sync - ? node_modules-sync - ? bower_components-sync + app-sync: + node_modules-sync: + bower_components-sync: diff --git a/docker-compose.yml b/docker-compose.yml index 2401d523cd..833a6046e9 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -9,8 +9,8 @@ services: - popcodeorg/popcode:latest command: npm start ports: - - "3000:3000" - - "3001:3001" + - '3000:3000' + - '3001:3001' volumes: - .:/app:cached - node_modules:/app/node_modules diff --git a/gulpfile.js b/gulpfile.js index 8bb6f4ef69..e583b27374 100644 --- a/gulpfile.js +++ b/gulpfile.js @@ -28,8 +28,7 @@ const staticDir = path.join(srcDir, 'static'); const bowerComponents = 'bower_components'; const postcssBrowsers = []; -const supportedBrowsers = - JSON.parse(fs.readFileSync('./config/browsers.json')); +const supportedBrowsers = JSON.parse(fs.readFileSync('./config/browsers.json')); forOwn(supportedBrowsers, (version, browser) => { let browserForPostcss = browser; if (browser === 'msie') { @@ -40,11 +39,8 @@ forOwn(supportedBrowsers, (version, browser) => { postcssBrowsers.push(`${browserForPostcss} >= ${version}`); }); -gulp.task( - 'static', - () => gulp. - src(path.join(staticDir, '**/*')). - pipe(gulp.dest(distDir)), +gulp.task('static', () => + gulp.src(path.join(staticDir, '**/*')).pipe(gulp.dest(distDir)), ); gulp.task('css', () => { @@ -60,47 +56,48 @@ gulp.task('css', () => { processors.push(cssnano()); } - return gulp. - src([ + return gulp + .src([ path.join(bowerComponents, 'normalize-css/normalize.css'), path.join(highlightStylesheetsDir, 'github.css'), path.join(stylesheetsDir, '**/*.css'), - ]). - pipe(concat('application.css')). - pipe(sourcemaps.init({loadMaps: true})). - pipe(postcss(processors)). - pipe(sourcemaps.write('./')). - pipe(gulp.dest(distDir)). - pipe(browserSync.stream()); + ]) + .pipe(concat('application.css')) + .pipe(sourcemaps.init({loadMaps: true})) + .pipe(postcss(processors)) + .pipe(sourcemaps.write('./')) + .pipe(gulp.dest(distDir)) + .pipe(browserSync.stream()); }); -gulp.task('js', () => new Promise((resolve, reject) => { - webpack( - webpackConfiguration(process.env.NODE_ENV), - (error, stats) => { - if (error) { - reject(error); - return; - } - - if (stats.hasErrors()) { - reject(new Error(stats.toJson().errors.join('\n\n'))); - return; - } - - if (stats.hasWarnings()) { - // eslint-disable-next-line no-console - console.warn(stats.toJson().warnings); - } - - resolve(stats); - }, - ); -})); +gulp.task( + 'js', + () => + new Promise((resolve, reject) => { + webpack(webpackConfiguration(process.env.NODE_ENV), (error, stats) => { + if (error) { + reject(error); + return; + } + + if (stats.hasErrors()) { + reject(new Error(stats.toJson().errors.join('\n\n'))); + return; + } + + if (stats.hasWarnings()) { + // eslint-disable-next-line no-console + console.warn(stats.toJson().warnings); + } + + resolve(stats); + }); + }), +); gulp.task('build', ['static', 'css', 'js']); -gulp.task('syncFirebase', async() => { +gulp.task('syncFirebase', async () => { const data = await pify(fs).readFile( path.resolve(__dirname, 'config/firebase-auth.json'), ); @@ -110,17 +107,20 @@ gulp.task('syncFirebase', async() => { } return new Promise((resolve, reject) => { - const req = https.request({ - hostname: `${config.firebaseApp}.firebaseio.com`, - path: `/.settings/rules.json?auth=${firebaseSecret}`, - method: 'PUT', - }, (res) => { - if (res.statusCode === 200) { - resolve(); - } else { - res.on('data', reject); - } - }); + const req = https.request( + { + hostname: `${config.firebaseApp}.firebaseio.com`, + path: `/.settings/rules.json?auth=${firebaseSecret}`, + method: 'PUT', + }, + res => { + if (res.statusCode === 200) { + resolve(); + } else { + res.on('data', reject); + } + }, + ); req.write(data); req.end(); @@ -144,30 +144,22 @@ gulp.task('browserSync', ['static'], () => { server: { baseDir: distDir, middleware: [ - webpackDevMiddleware( - compiler, - { - lazy: false, - }, - ), + webpackDevMiddleware(compiler, { + lazy: false, + }), ], }, }); }); -gulp.task( - 'purgeCache', - () => - cloudflare({ - email: process.env.CLOUDFLARE_EMAIL, - key: process.env.CLOUDFLARE_KEY, - }).zones.purgeCache( - process.env.CLOUDFLARE_ZONE, - { - files: [ - `https://${process.env.HOSTNAME}/index.html`, - `https://${process.env.HOSTNAME}/application.css`, - ], - }, - ), +gulp.task('purgeCache', () => + cloudflare({ + email: process.env.CLOUDFLARE_EMAIL, + key: process.env.CLOUDFLARE_KEY, + }).zones.purgeCache(process.env.CLOUDFLARE_ZONE, { + files: [ + `https://${process.env.HOSTNAME}/index.html`, + `https://${process.env.HOSTNAME}/application.css`, + ], + }), ); diff --git a/jest.config.js b/jest.config.js index fe70542073..86d35c1862 100644 --- a/jest.config.js +++ b/jest.config.js @@ -10,10 +10,7 @@ module.exports = { '@factories/(.*)$': '/__factories__/$1', '\\.(html|svg)': '/__mocks__/fileMock.js', }, - testPathIgnorePatterns: [ - '/node_modules/', - '/bower_components/', - ], + testPathIgnorePatterns: ['/node_modules/', '/bower_components/'], transformIgnorePatterns: ['node_modules/(?!(lodash-es)/)'], setupFilesAfterEnv: ['jest-extended'], }; diff --git a/karma.conf.js b/karma.conf.js index 786f3e3221..7c014efc80 100644 --- a/karma.conf.js +++ b/karma.conf.js @@ -51,7 +51,7 @@ module.exports = function configure(config) { if (browserStackAvailable) { const customLaunchers = {}; - allBrowsers.forEach((browser) => { + allBrowsers.forEach(browser => { customLaunchers[`browserStack${browser[0]}${browser[2]}`] = { base: 'BrowserStack', browser: browser[0], diff --git a/src/actions/applicationLoaded.js b/src/actions/applicationLoaded.js index c7a7726f6b..87b82f9f2c 100644 --- a/src/actions/applicationLoaded.js +++ b/src/actions/applicationLoaded.js @@ -1,5 +1,3 @@ import {createAction} from 'redux-actions'; -export default createAction( - 'APPLICATION_LOADED', -); +export default createAction('APPLICATION_LOADED'); diff --git a/src/actions/assignments.js b/src/actions/assignments.js index 086abb1879..c23df43180 100644 --- a/src/actions/assignments.js +++ b/src/actions/assignments.js @@ -2,8 +2,11 @@ import {createAction} from 'redux-actions'; export const createAssignment = createAction( 'CREATE_ASSIGNMENT', - (selectedCourseId, dueDate, assignmentState) => - ({selectedCourseId, dueDate, assignmentState}), + (selectedCourseId, dueDate, assignmentState) => ({ + selectedCourseId, + dueDate, + assignmentState, + }), ); export const assignmentCreated = createAction( @@ -11,6 +14,4 @@ export const assignmentCreated = createAction( assignment => ({assignment}), ); -export const assignmentNotCreated = createAction( - 'ASSIGNMENT_NOT_CREATED', -); +export const assignmentNotCreated = createAction('ASSIGNMENT_NOT_CREATED'); diff --git a/src/actions/clients.js b/src/actions/clients.js index 320a64cbda..61ea34d3ad 100644 --- a/src/actions/clients.js +++ b/src/actions/clients.js @@ -9,12 +9,12 @@ export const snapshotImported = createAction( (projectKey, project) => ({projectKey, project}), ); export const snapshotImportError = createAction('SNAPSHOT_IMPORT_ERROR'); -export const projectRestoredFromLastSession = - createAction('PROJECT_RESTORED_FROM_LAST_SESSION'); -export const exportProject = createAction( - 'EXPORT_PROJECT', - exportType => ({exportType}), +export const projectRestoredFromLastSession = createAction( + 'PROJECT_RESTORED_FROM_LAST_SESSION', ); +export const exportProject = createAction('EXPORT_PROJECT', exportType => ({ + exportType, +})); export const projectExported = createAction( 'PROJECT_EXPORTED', (url, exportType, projectKey, exportData) => ({ @@ -23,8 +23,9 @@ export const projectExported = createAction( projectKey, exportData, }), - (_url, _exportType, _projectKey, _exportData, timestamp = Date.now()) => - ({timestamp}), + (_url, _exportType, _projectKey, _exportData, timestamp = Date.now()) => ({ + timestamp, + }), ); export const projectExportError = createAction( 'PROJECT_EXPORT_ERROR', diff --git a/src/actions/compiledProjects.js b/src/actions/compiledProjects.js index 8fad5c3d4c..d964dccada 100644 --- a/src/actions/compiledProjects.js +++ b/src/actions/compiledProjects.js @@ -11,7 +11,6 @@ export const projectCompilationFailed = createAction( 'PROJECT_COMPILATION_FAILED', ); -export const refreshPreview = createAction( - 'REFRESH_PREVIEW', - timestamp => ({timestamp}), -); +export const refreshPreview = createAction('REFRESH_PREVIEW', timestamp => ({ + timestamp, +})); diff --git a/src/actions/console.js b/src/actions/console.js index ccc281062f..da0590bdbb 100644 --- a/src/actions/console.js +++ b/src/actions/console.js @@ -4,14 +4,12 @@ import uuid from 'uuid/v4'; export const consoleValueProduced = createAction( 'CONSOLE_VALUE_PRODUCED', - (key, value, compiledProjectKey) => - ({key, value, compiledProjectKey}), + (key, value, compiledProjectKey) => ({key, value, compiledProjectKey}), ); export const consoleErrorProduced = createAction( 'CONSOLE_ERROR_PRODUCED', - (key, compiledProjectKey, error) => - ({key, compiledProjectKey, error}), + (key, compiledProjectKey, error) => ({key, compiledProjectKey, error}), ); export const evaluateConsoleEntry = createAction( @@ -20,17 +18,11 @@ export const evaluateConsoleEntry = createAction( (_input, key = uuid().toString()) => ({key}), ); -export const clearConsoleEntries = createAction( - 'CLEAR_CONSOLE_ENTRIES', -); +export const clearConsoleEntries = createAction('CLEAR_CONSOLE_ENTRIES'); -export const previousConsoleHistory = createAction( - 'PREVIOUS_CONSOLE_HISTORY', -); +export const previousConsoleHistory = createAction('PREVIOUS_CONSOLE_HISTORY'); -export const nextConsoleHistory = createAction( - 'NEXT_CONSOLE_HISTORY', -); +export const nextConsoleHistory = createAction('NEXT_CONSOLE_HISTORY'); export const consoleInputChanged = createAction( 'CONSOLE_INPUT_CHANGED', diff --git a/src/actions/index.js b/src/actions/index.js index 71eab48168..591b748aa4 100644 --- a/src/actions/index.js +++ b/src/actions/index.js @@ -1,8 +1,6 @@ import applicationLoaded from './applicationLoaded'; -import { - createAssignment, -} from './assignments'; +import {createAssignment} from './assignments'; import { createSnapshot, @@ -50,9 +48,7 @@ import { toggleArchivedView, } from './ui'; -import { - addRuntimeError, -} from './errors'; +import {addRuntimeError} from './errors'; import { dismissAccountMigration, @@ -82,9 +78,7 @@ import { previousConsoleHistory, } from './console'; -import { - updateResizableFlex, -} from './resizableFlex'; +import {updateResizableFlex} from './resizableFlex'; export { beautifyProjectSource, diff --git a/src/actions/projects.js b/src/actions/projects.js index 4e13516617..f5ff37402d 100644 --- a/src/actions/projects.js +++ b/src/actions/projects.js @@ -1,9 +1,8 @@ import {createAction} from 'redux-actions'; -export const projectCreated = createAction( - 'PROJECT_CREATED', - projectKey => ({projectKey}), -); +export const projectCreated = createAction('PROJECT_CREATED', projectKey => ({ + projectKey, +})); export const createProject = createAction('CREATE_PROJECT'); @@ -18,9 +17,7 @@ export const updateProjectSource = createAction( (_projectKey, _language, _newValue, timestamp = Date.now()) => ({timestamp}), ); -export const beautifyProjectSource = createAction( - 'BEAUTIFY_PROJECT_SOURCE', -); +export const beautifyProjectSource = createAction('BEAUTIFY_PROJECT_SOURCE'); export const projectBeautified = createAction( 'PROJECT_BEAUTIFIED', @@ -63,22 +60,20 @@ export const gistImported = createAction( (projectKey, gistData) => ({projectKey, gistData}), ); -export const gistNotFound = createAction( - 'GIST_NOT_FOUND', - gistId => ({gistId}), -); +export const gistNotFound = createAction('GIST_NOT_FOUND', gistId => ({ + gistId, +})); -export const gistImportError = createAction( - 'GIST_IMPORT_ERROR', - gistId => ({gistId}), -); +export const gistImportError = createAction('GIST_IMPORT_ERROR', gistId => ({ + gistId, +})); export const projectsLoaded = createAction('PROJECTS_LOADED'); -export const projectSuccessfullySaved = - createAction('PROJECT_SUCCESSFULLY_SAVED'); - -export const archiveProject = createAction( - 'ARCHIVE_PROJECT', - projectKey => ({projectKey}), +export const projectSuccessfullySaved = createAction( + 'PROJECT_SUCCESSFULLY_SAVED', ); + +export const archiveProject = createAction('ARCHIVE_PROJECT', projectKey => ({ + projectKey, +})); diff --git a/src/actions/ui.js b/src/actions/ui.js index 0796c4954f..f44ff56edf 100644 --- a/src/actions/ui.js +++ b/src/actions/ui.js @@ -12,17 +12,11 @@ export const editorFocusedRequestedLine = createAction( 'EDITOR_FOCUSED_REQUESTED_LINE', ); -export const startDragColumnDivider = createAction( - 'START_DRAG_COLUMN_DIVIDER', -); +export const startDragColumnDivider = createAction('START_DRAG_COLUMN_DIVIDER'); -export const stopDragColumnDivider = createAction( - 'STOP_DRAG_COLUMN_DIVIDER', -); +export const stopDragColumnDivider = createAction('STOP_DRAG_COLUMN_DIVIDER'); -export const popOutProject = createAction( - 'POP_OUT_PROJECT', -); +export const popOutProject = createAction('POP_OUT_PROJECT'); export const notificationTriggered = createAction( 'NOTIFICATION_TRIGGERED', @@ -39,17 +33,11 @@ export const updateNotificationMetadata = createAction( (type, metadata) => ({type, metadata}), ); -export const toggleEditorTextSize = createAction( - 'TOGGLE_EDITOR_TEXT_SIZE', -); +export const toggleEditorTextSize = createAction('TOGGLE_EDITOR_TEXT_SIZE'); -export const toggleTopBarMenu = createAction( - 'TOGGLE_TOP_BAR_MENU', -); +export const toggleTopBarMenu = createAction('TOGGLE_TOP_BAR_MENU'); -export const closeTopBarMenu = createAction( - 'CLOSE_TOP_BAR_MENU', -); +export const closeTopBarMenu = createAction('CLOSE_TOP_BAR_MENU'); export const startEditingInstructions = createAction( 'START_EDITING_INSTRUCTIONS', @@ -61,31 +49,18 @@ export const cancelEditingInstructions = createAction( 'CANCEL_EDITING_INSTRUCTIONS', ); -export const showSaveIndicator = createAction( - 'SHOW_SAVE_INDICATOR', -); +export const showSaveIndicator = createAction('SHOW_SAVE_INDICATOR'); -export const hideSaveIndicator = createAction( - 'HIDE_SAVE_INDICATOR', -); +export const hideSaveIndicator = createAction('HIDE_SAVE_INDICATOR'); -export const openAssignmentCreator = createAction( - 'OPEN_ASSIGNMENT_CREATOR', -); +export const openAssignmentCreator = createAction('OPEN_ASSIGNMENT_CREATOR'); -export const closeAssignmentCreator = createAction( - 'CLOSE_ASSIGNMENT_CREATOR', -); +export const closeAssignmentCreator = createAction('CLOSE_ASSIGNMENT_CREATOR'); -export const coursesLoaded = createAction( - 'COURSES_LOADED', - courses => ({courses}), -); +export const coursesLoaded = createAction('COURSES_LOADED', courses => ({ + courses, +})); -export const coursesFullyLoaded = createAction( - 'COURSES_FULLY_LOADED', -); +export const coursesFullyLoaded = createAction('COURSES_FULLY_LOADED'); -export const toggleArchivedView = createAction( - 'TOGGLE_ARCHIVED_VIEW', -); +export const toggleArchivedView = createAction('TOGGLE_ARCHIVED_VIEW'); diff --git a/src/actions/user.js b/src/actions/user.js index 3f588069e4..d9a7799d89 100644 --- a/src/actions/user.js +++ b/src/actions/user.js @@ -1,9 +1,6 @@ import {createAction} from 'redux-actions'; -export const logIn = createAction( - 'LOG_IN', - provider => ({provider}), -); +export const logIn = createAction('LOG_IN', provider => ({provider})); export const linkGithubIdentity = createAction('LINK_GITHUB_IDENTITY'); @@ -31,11 +28,13 @@ export const accountMigrationNeeded = createAction( export const startAccountMigration = createAction('START_ACCOUNT_MIGRATION'); -export const dismissAccountMigration = - createAction('DISMISS_ACCOUNT_MIGRATION'); +export const dismissAccountMigration = createAction( + 'DISMISS_ACCOUNT_MIGRATION', +); -export const accountMigrationUndoPeriodExpired = - createAction('ACCOUNT_MIGRATION_UNDO_PERIOD_EXPIRED'); +export const accountMigrationUndoPeriodExpired = createAction( + 'ACCOUNT_MIGRATION_UNDO_PERIOD_EXPIRED', +); export const accountMigrationComplete = createAction( 'ACCOUNT_MIGRATION_COMPLETE', diff --git a/src/clients/firebase.js b/src/clients/firebase.js index bdddc4862d..8ab736bea9 100644 --- a/src/clients/firebase.js +++ b/src/clients/firebase.js @@ -36,25 +36,28 @@ for (const scope of GOOGLE_SCOPES) { const {auth, loadDatabase} = buildFirebase(); async function loadDatabaseSdk() { - return retryingFailedImports( - () => import( + return retryingFailedImports(() => + import( /* webpackChunkName: "mainAsync" */ - '@firebase/database' // eslint-disable-line comma-dangle + '@firebase/database' ), ); } function buildFirebase(appName = undefined) { - const app = firebase.initializeApp({ - apiKey: config.firebaseApiKey, - authDomain: `${config.firebaseApp}.firebaseapp.com`, - databaseURL: `https://${config.firebaseApp}.firebaseio.com`, - }, appName); + const app = firebase.initializeApp( + { + apiKey: config.firebaseApiKey, + authDomain: `${config.firebaseApp}.firebaseapp.com`, + databaseURL: `https://${config.firebaseApp}.firebaseio.com`, + }, + appName, + ); return { auth: firebase.auth(app), - loadDatabase: once(async() => { + loadDatabase: once(async () => { await loadDatabaseSdk(); return firebase.database(app); }), @@ -62,7 +65,7 @@ function buildFirebase(appName = undefined) { } export function onAuthStateChanged(listener) { - return auth.onAuthStateChanged((user) => { + return auth.onAuthStateChanged(user => { listener({user}); }); } @@ -87,27 +90,33 @@ export async function createProjectSnapshot(project) { const snapshotKey = uuid().toString(); const database = await loadDatabase(); const projectForSnapshot = getProjectforSnapshot(project); - await database.ref('snapshots').child(snapshotKey).set(projectForSnapshot); + await database + .ref('snapshots') + .child(snapshotKey) + .set(projectForSnapshot); return snapshotKey; } export async function loadProjectSnapshot(snapshotKey) { const database = await loadDatabase(); - const event = - await database.ref('snapshots').child(snapshotKey).once('value'); + const event = await database + .ref('snapshots') + .child(snapshotKey) + .once('value'); return event.val(); } export async function saveProject(uid, project) { const userWorkspace = await workspace(uid); - await userWorkspace.child('projects').child(project.projectKey). - setWithPriority(project, -Date.now()); + await userWorkspace + .child('projects') + .child(project.projectKey) + .setWithPriority(project, -Date.now()); } export async function loadCredentialsForUser(uid) { const database = await loadDatabase(); - const credentialEvent = - await database.ref(`authTokens/${uid}`).once('value'); + const credentialEvent = await database.ref(`authTokens/${uid}`).once('value'); return values(credentialEvent.val()); } @@ -130,8 +139,7 @@ export async function signIn(provider) { } export async function linkGithub() { - const {credential} = - await auth.currentUser.linkWithPopup(githubAuthProvider); + const {credential} = await auth.currentUser.linkWithPopup(githubAuthProvider); return {user: auth.currentUser, credential}; } @@ -146,8 +154,9 @@ export async function migrateAccount(inboundAccountCredential) { const inboundAccountFirebase = buildFirebase('migration'); const {auth: inboundAccountAuth} = inboundAccountFirebase; try { - await inboundAccountAuth. - signInAndRetrieveDataWithCredential(inboundAccountCredential); + await inboundAccountAuth.signInAndRetrieveDataWithCredential( + inboundAccountCredential, + ); const inboundUid = inboundAccountAuth.currentUser.uid; await logMigration(inboundUid, 'attempt'); @@ -175,9 +184,9 @@ async function migrateProjects({ const currentAccountDatabase = await loadDatabase(); const inboundAccountDatabase = await loadinboundAccountDatabase(); - const allProjectsValue = await inboundAccountDatabase. - ref(`workspaces/${inboundAccountAuth.currentUser.uid}/projects`). - once('value'); + const allProjectsValue = await inboundAccountDatabase + .ref(`workspaces/${inboundAccountAuth.currentUser.uid}/projects`) + .once('value'); if (isNull(allProjectsValue)) { return []; @@ -188,21 +197,18 @@ async function migrateProjects({ return []; } - await currentAccountDatabase. - ref(`workspaces/${auth.currentUser.uid}/projects`). - update(allProjects); + await currentAccountDatabase + .ref(`workspaces/${auth.currentUser.uid}/projects`) + .update(allProjects); return values(allProjects); } async function logMigration(inboundUid, eventName) { - bugsnagClient.notify( - new Error(`Account migration ${eventName}`), - { - metaData: {migration: {inboundUid}}, - severity: 'info', - }, - ); + bugsnagClient.notify(new Error(`Account migration ${eventName}`), { + metaData: {migration: {inboundUid}}, + severity: 'info', + }); } async function signInWithGithub() { @@ -211,10 +217,12 @@ async function signInWithGithub() { async function signInWithGoogle() { const gapi = getGapiSync(); - const googleUser = - await gapi.auth2.getAuthInstance().signIn({prompt: 'select_account'}); - const googleCredential = - googleAuthProvider.credential(googleUser.getAuthResponse().id_token); + const googleUser = await gapi.auth2 + .getAuthInstance() + .signIn({prompt: 'select_account'}); + const googleCredential = googleAuthProvider.credential( + googleUser.getAuthResponse().id_token, + ); return auth.signInAndRetrieveDataWithCredential(googleCredential); } @@ -226,10 +234,7 @@ export async function signOut() { return auth.signOut(); } -export async function saveUserCredential({ - user: {uid}, - credential, -}) { +export async function saveUserCredential({user: {uid}, credential}) { await saveCredentialForUser(uid, credential); } @@ -239,9 +244,9 @@ export async function saveCredentialForCurrentUser(credential) { async function saveCredentialForUser(uid, credential) { const database = await loadDatabase(); - await database. - ref(`authTokens/${providerPath(uid, credential.providerId)}`). - set(credential); + await database + .ref(`authTokens/${providerPath(uid, credential.providerId)}`) + .set(credential); } async function deleteCredentialForUser(uid, providerId) { @@ -264,10 +269,8 @@ export function getSessionUid() { export function setSessionUid() { const uid = get(auth, 'currentUser.uid'); if (!isNil(uid)) { - Cookies.set( - VALID_SESSION_UID_COOKIE, - uid, - {expires: new Date(Date.now() + SESSION_TTL_MS)}, - ); + Cookies.set(VALID_SESSION_UID_COOKIE, uid, { + expires: new Date(Date.now() + SESSION_TTL_MS), + }); } } diff --git a/src/clients/github.js b/src/clients/github.js index ad92eb6547..4fd120c215 100644 --- a/src/clients/github.js +++ b/src/clients/github.js @@ -15,9 +15,9 @@ const NETWORK_ERROR = 'Network Error'; export class EmptyGistError extends ExtendableError {} function normalizeTitle(title) { - const titleWithoutPunctuationAndWhitespace = title. - replace(/[^\w\s]|_/gu, ''). - replace(/\W/gu, '-'); + const titleWithoutPunctuationAndWhitespace = title + .replace(/[^\w\s]|_/gu, '') + .replace(/\W/gu, '-'); return titleWithoutPunctuationAndWhitespace; } @@ -43,36 +43,32 @@ async function createRepoFromProject(project, accessToken) { const repoName = `${title}`; let duplicateNameFailureCount = 0; let fullRepoName = ''; - const {data} = - await performWithRetries( - () => { - const suffix = duplicateNameFailureCount === 0 ? - '' : - `-${duplicateNameFailureCount}`; - fullRepoName = `${repoName}${suffix}`; - return github.getUser().createRepo({ - name: fullRepoName, - auto_init: true, - }); - }, - (errorMessage) => { - const shouldRetry = errorMessage.includes('Unprocessable Entity') || - errorMessage === NETWORK_ERROR; - if (errorMessage.includes('Unprocessable Entity')) { - duplicateNameFailureCount += 1; - } - return shouldRetry; - }, - {}, - ); + const {data} = await performWithRetries( + () => { + const suffix = + duplicateNameFailureCount === 0 ? '' : `-${duplicateNameFailureCount}`; + fullRepoName = `${repoName}${suffix}`; + return github.getUser().createRepo({ + name: fullRepoName, + auto_init: true, + }); + }, + errorMessage => { + const shouldRetry = + errorMessage.includes('Unprocessable Entity') || + errorMessage === NETWORK_ERROR; + if (errorMessage.includes('Unprocessable Entity')) { + duplicateNameFailureCount += 1; + } + return shouldRetry; + }, + {}, + ); const userName = data.owner.login; - await performWithRetryNetworkErrors( - () => github.getRepo( - userName, - fullRepoName, - ).deleteFile(MASTER, 'README.md'), + await performWithRetryNetworkErrors(() => + github.getRepo(userName, fullRepoName).deleteFile(MASTER, 'README.md'), ); await createBranch(github, userName, fullRepoName, MASTER, GH_PAGES); @@ -91,16 +87,16 @@ async function updateRepoFromProject(project, accessToken) { const github = await createClient(accessToken); const repoName = project.externalLocations.githubRepoName; - const {data: userData} = await performWithRetryNetworkErrors( - () => github.getUser().getProfile(), + const {data: userData} = await performWithRetryNetworkErrors(() => + github.getUser().getProfile(), ); const userName = userData.login; await createRepoFiles(github, project, userName, repoName); - const {data} = await performWithRetryNetworkErrors( - () => github.getRepo(userName, repoName).getDetails(), + const {data} = await performWithRetryNetworkErrors(() => + github.getRepo(userName, repoName).getDetails(), ); return { @@ -127,8 +123,9 @@ export async function createGistFromProject(project, accessToken) { return Promise.reject(new EmptyGistError()); } - const response = - await performWithRetryNetworkErrors(() => github.getGist().create(gist)); + const response = await performWithRetryNetworkErrors(() => + github.getGist().create(gist), + ); return updateGistWithImportUrl(github, response.data); } @@ -136,8 +133,9 @@ export async function createGistFromProject(project, accessToken) { export async function loadGistFromId(gistId) { const github = await createClient(); const gist = github.getGist(gistId); - const response = - await performWithRetryNetworkErrors(() => gist.read(), {retries: 3}); + const response = await performWithRetryNetworkErrors(() => gist.read(), { + retries: 3, + }); return response.data; } @@ -176,7 +174,7 @@ function buildGistFromProject(project) { return { description: 'Exported from Popcode.', - 'public': true, + public: true, files, }; } @@ -188,8 +186,9 @@ async function updateGistWithImportUrl(github, gistData) { uri.search = `gist=${gistData.id}`; const description = `${gistData.description} Click to import: ${uri.href}`; - const response = - await performWithRetryNetworkErrors(() => gist.update({description})); + const response = await performWithRetryNetworkErrors(() => + gist.update({description}), + ); return response.data; } @@ -220,15 +219,10 @@ async function createSourceFileInRepo( fileName, source, ) { - await performWithRetryNetworkErrors( - () => github.getRepo(userName, repoName). - writeFile( - branchName, - fileName, - source, - COMMIT_MESSAGE, - {}, - ), + await performWithRetryNetworkErrors(() => + github + .getRepo(userName, repoName) + .writeFile(branchName, fileName, source, COMMIT_MESSAGE, {}), ); } @@ -283,36 +277,28 @@ async function createPreviewFile(github, project, userName, repoName) { ); } -async function createBranch( - github, - userName, - repoName, - oldBranch, - newBranch, -) { - await performWithRetryNetworkErrors( - () => github.getRepo(userName, repoName). - createBranch(oldBranch, newBranch), +async function createBranch(github, userName, repoName, oldBranch, newBranch) { + await performWithRetryNetworkErrors(() => + github.getRepo(userName, repoName).createBranch(oldBranch, newBranch), ); } async function updateRepoDescription(github, userName, repoName) { const url = `https://${userName}.github.io/${repoName}`; - await performWithRetryNetworkErrors( - () => github.getRepo(userName, repoName). - updateRepository({ - name: repoName, - description: url, - homepage: url, - }), + await performWithRetryNetworkErrors(() => + github.getRepo(userName, repoName).updateRepository({ + name: repoName, + description: url, + homepage: url, + }), ); } async function createClient(token = null) { - const {'default': GitHub} = await retryingFailedImports( - () => import( + const {default: GitHub} = await retryingFailedImports(() => + import( /* webpackChunkName: "mainAsync" */ - 'github-api' // eslint-disable-line comma-dangle + 'github-api' ), ); diff --git a/src/clients/googleAnalytics.js b/src/clients/googleAnalytics.js index 3417cdb3f5..1b3e371509 100644 --- a/src/clients/googleAnalytics.js +++ b/src/clients/googleAnalytics.js @@ -3,15 +3,12 @@ import ReactGA from 'react-ga'; import config from '../config'; const cookieDomain = - (window.location.hostname === 'localhost') ? - 'none' : - window.location.hostname; + window.location.hostname === 'localhost' ? 'none' : window.location.hostname; export function init() { - ReactGA.initialize( - config.googleAnalyticsTrackingId, - {gaOptions: {cookieDomain}}, - ); + ReactGA.initialize(config.googleAnalyticsTrackingId, { + gaOptions: {cookieDomain}, + }); } export function logPageview() { diff --git a/src/clients/googleClassroom.js b/src/clients/googleClassroom.js index 6085817c07..a621ccb7b1 100644 --- a/src/clients/googleClassroom.js +++ b/src/clients/googleClassroom.js @@ -1,9 +1,7 @@ import qs from 'qs'; import {AssignmentState} from '../enums'; -import { - loadAndConfigureGapi, -} from '../services/gapi'; +import {loadAndConfigureGapi} from '../services/gapi'; const BASE_URL = 'https://classroom.google.com/u/0/share?'; diff --git a/src/clients/localStorage.js b/src/clients/localStorage.js index 6712331407..30bb4f1c33 100644 --- a/src/clients/localStorage.js +++ b/src/clients/localStorage.js @@ -2,10 +2,13 @@ const PROJECT_STORAGE_KEY = 'last-closed-session-project-state'; const GRACE_PERIOD = 5 * 60 * 1000; export function dehydrateProject(project) { - localStorage.setItem(PROJECT_STORAGE_KEY, JSON.stringify({ - dehydratedAt: Date.now(), - project, - })); + localStorage.setItem( + PROJECT_STORAGE_KEY, + JSON.stringify({ + dehydratedAt: Date.now(), + project, + }), + ); } export function rehydrateProject() { diff --git a/src/components/AccountMigration.jsx b/src/components/AccountMigration.jsx index 4dc6f2dc22..ef45fa6cb0 100644 --- a/src/components/AccountMigration.jsx +++ b/src/components/AccountMigration.jsx @@ -13,8 +13,7 @@ import {AccountMigrationState} from '../enums'; import AccountMigrationComplete from './AccountMigrationComplete'; import AccountMigrationInProgress from './AccountMigrationInProgress'; -import AccountMigrationUndoGracePeriod - from './AccountMigrationUndoGracePeriod'; +import AccountMigrationUndoGracePeriod from './AccountMigrationUndoGracePeriod'; import Modal from './Modal'; import ProposedAccountMigration from './ProposedAccountMigration'; import AccountMigrationError from './AccountMigrationError'; @@ -33,9 +32,11 @@ export default function AccountMigration({

- {t(`account-migration.header.${ - migration.state.key.toLowerCase().replace(/_/gu, '-') - }`)} + {t( + `account-migration.header.${migration.state.key + .toLowerCase() + .replace(/_/gu, '-')}`, + )}

diff --git a/src/components/AccountMigrationComplete.jsx b/src/components/AccountMigrationComplete.jsx index 62d76dd00c..8786617963 100644 --- a/src/components/AccountMigrationComplete.jsx +++ b/src/components/AccountMigrationComplete.jsx @@ -6,14 +6,10 @@ import PropTypes from 'prop-types'; export default function AccountMigrationComplete({onDismiss}) { return ( -

- {t('account-migration.complete')} -

+

{t('account-migration.complete')}

diff --git a/src/components/AssignmentCreatorForm.jsx b/src/components/AssignmentCreatorForm.jsx index a9f9a8d30d..9e80438e06 100644 --- a/src/components/AssignmentCreatorForm.jsx +++ b/src/components/AssignmentCreatorForm.jsx @@ -42,21 +42,15 @@ export default function AssignmentCreatorForm({ return (
- + - { - courses.map(course => ( - - )).valueSeq() - } + )) + .valueSeq()}
@@ -71,51 +65,51 @@ export default function AssignmentCreatorForm({ />
- { - isAssignmentExportInProgress ? + {isAssignmentExportInProgress ? ( + + ) : ( + <> + + : - <> - - - - - } + {t('assignment-creator.assign-button')} + + + )}
); diff --git a/src/components/AssignmentCreatorSelectField.jsx b/src/components/AssignmentCreatorSelectField.jsx index f1d5ffb6fd..add6e0f06b 100644 --- a/src/components/AssignmentCreatorSelectField.jsx +++ b/src/components/AssignmentCreatorSelectField.jsx @@ -12,23 +12,18 @@ export default function AssignmentCreatorSelectField({ return (
- {children}
- { - (touched && error) && ( - - {error} - - ) - } + {touched && error && ( + + {error} + + )}
); } diff --git a/src/components/AssignmentCreatorTextField.jsx b/src/components/AssignmentCreatorTextField.jsx index fe02a5f02d..d4495e1ce6 100644 --- a/src/components/AssignmentCreatorTextField.jsx +++ b/src/components/AssignmentCreatorTextField.jsx @@ -18,18 +18,14 @@ export default function AssignmentCreatorTextField({ />
- - {t('assignment-creator.value-label', {valueLabel})} - + {t('assignment-creator.value-label', {valueLabel})}
- { - (touched && error) && ( - - {error} - - ) - } + {touched && error && ( + + {error} + + )}
); diff --git a/src/components/BrowserError.jsx b/src/components/BrowserError.jsx index 90b932814f..de92e7ba0d 100644 --- a/src/components/BrowserError.jsx +++ b/src/components/BrowserError.jsx @@ -20,9 +20,7 @@ function BrowserError({browser}) {

{t('bad-browser.message', {name: browserName})}

- - {t('bad-browser.download')} - + {t('bad-browser.download')}

); diff --git a/src/components/CollapsedComponent.jsx b/src/components/CollapsedComponent.jsx index f54cdcfc17..5bc1d02796 100644 --- a/src/components/CollapsedComponent.jsx +++ b/src/components/CollapsedComponent.jsx @@ -15,22 +15,14 @@ export default function CollapsedComponent({ return (
- {text} - {' '} - + {text}
); diff --git a/src/components/Console.jsx b/src/components/Console.jsx index 94a0a6f284..b64fd4fd48 100644 --- a/src/components/Console.jsx +++ b/src/components/Console.jsx @@ -1,8 +1,5 @@ import classnames from 'classnames'; -import { - faBan, - faChevronDown, -} from '@fortawesome/free-solid-svg-icons'; +import {faBan, faChevronDown} from '@fortawesome/free-solid-svg-icons'; import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; import partial from 'lodash-es/partial'; import React from 'react'; @@ -43,9 +40,9 @@ export default function Console({ onClick={onConsoleClicked} >
- {history.map((entry, key) => { - const isActive = - currentCompiledProjectKey === entry.evaluatedByCompiledProjectKey; - return ( - // eslint-disable-next-line react/no-array-index-key - - ); - }).valueSeq().reverse()} + {history + .map((entry, key) => { + const isActive = + currentCompiledProjectKey === entry.evaluatedByCompiledProjectKey; + return ; + }) + .valueSeq() + .reverse()}
); return ( -
+
- {t('workspace.components.console')} - {' '} + {t('workspace.components.console')}{' '}
{ + onClick={e => { e.stopPropagation(); onClearConsoleEntries(); }} diff --git a/src/components/ConsoleExpression.jsx b/src/components/ConsoleExpression.jsx index 5cc0970a6e..71d590f791 100644 --- a/src/components/ConsoleExpression.jsx +++ b/src/components/ConsoleExpression.jsx @@ -14,13 +14,9 @@ export default function ConsoleExpression({entry: {expression}, isActive}) { return (
diff --git a/src/components/ConsoleInput.jsx b/src/components/ConsoleInput.jsx index 8cf4e9e777..d6c2f03bd8 100644 --- a/src/components/ConsoleInput.jsx +++ b/src/components/ConsoleInput.jsx @@ -20,9 +20,7 @@ export default class ConsoleInput extends Component { bindAll(this, '_ref'); } - componentDidUpdate({ - isTextSizeLarge: prevIsTextSizeLarge, - }) { + componentDidUpdate({isTextSizeLarge: prevIsTextSizeLarge}) { const { isTextSizeLarge, requestedFocusedLine, @@ -61,7 +59,7 @@ export default class ConsoleInput extends Component { } = this.props; if (containerElement) { - const editor = this._editor = createAceEditor(containerElement); + const editor = (this._editor = createAceEditor(containerElement)); const session = createAceSessionWithoutWorker('javascript'); editor.setSession(session); editor.renderer.setShowGutter(false); diff --git a/src/components/ConsoleOutput.jsx b/src/components/ConsoleOutput.jsx index d8361acefb..faa853f1b0 100644 --- a/src/components/ConsoleOutput.jsx +++ b/src/components/ConsoleOutput.jsx @@ -9,22 +9,18 @@ import {ConsoleEntry} from '../records'; export default function ConsoleOutput({entry, isActive}) { const {expression, value, error} = entry; - const chevron = expression ? - (
+ const chevron = expression ? ( +
-
) : - null; +
+ ) : null; if (!isNil(value)) { return (
{chevron} {value} @@ -35,12 +31,9 @@ export default function ConsoleOutput({entry, isActive}) { if (!isNil(error)) { return (
{error.text}
diff --git a/src/components/Editor.jsx b/src/components/Editor.jsx index 81fdcf6eed..5f480ccc3a 100644 --- a/src/components/Editor.jsx +++ b/src/components/Editor.jsx @@ -30,18 +30,10 @@ class Editor extends React.Component { } }, RESIZE_THROTTLE); - bindAll( - this, - '_handleWindowResize', - '_resizeEditor', - '_setupEditor', - ); + bindAll(this, '_handleWindowResize', '_resizeEditor', '_setupEditor'); this.render = constant( -
, +
, ); } @@ -87,8 +79,9 @@ class Editor extends React.Component { } _focusRequestedLine(requestedFocusedLine) { - if (get(requestedFocusedLine, 'component') !== - `editor.${this.props.language}`) { + if ( + get(requestedFocusedLine, 'component') !== `editor.${this.props.language}` + ) { return; } diff --git a/src/components/EditorContainer.jsx b/src/components/EditorContainer.jsx index f4fd996e9b..1639d158f6 100644 --- a/src/components/EditorContainer.jsx +++ b/src/components/EditorContainer.jsx @@ -6,39 +6,36 @@ import {t} from 'i18next'; import prefix from '../services/inlineStylePrefixer'; -const EditorContainer = forwardRef(( - {children, language, source, style, onHide}, - ref, -) => { - let helpText; +const EditorContainer = forwardRef( + ({children, language, source, style, onHide}, ref) => { + let helpText; - if (source === '') { - helpText = ( -
- {t('editors.help-text', {language})} -
- ); - } + if (source === '') { + helpText = ( +
+ {t('editors.help-text', {language})} +
+ ); + } - return ( -
+ return (
- {t(`languages.${language}`)} - {' '} - +
+ {t(`languages.${language}`)} +
+ {helpText} + {children}
- {helpText} - {children} -
- ); -}); + ); + }, +); EditorContainer.propTypes = { children: PropTypes.node.isRequired, diff --git a/src/components/EditorsColumn.jsx b/src/components/EditorsColumn.jsx index 6b47624ced..e44ea57d30 100644 --- a/src/components/EditorsColumn.jsx +++ b/src/components/EditorsColumn.jsx @@ -51,11 +51,7 @@ export default function EditorsColumn({ source={currentProject.sources[language]} textSizeIsLarge={isTextSizeLarge} onAutoFormat={onAutoFormat} - onInput={partial( - onEditorInput, - currentProject.projectKey, - language, - )} + onInput={partial(onEditorInput, currentProject.projectKey, language)} onRequestedLineFocused={onRequestedLineFocused} /> , @@ -67,10 +63,9 @@ export default function EditorsColumn({ onDrag={partial(onResizableFlexDividerDrag, index)} >
, ); @@ -81,11 +76,7 @@ export default function EditorsColumn({ return null; } - return ( -
- {editors} -
- ); + return
{editors}
; } EditorsColumn.propTypes = { diff --git a/src/components/ErrorItem.jsx b/src/components/ErrorItem.jsx index b828c51a63..e6783fbd45 100644 --- a/src/components/ErrorItem.jsx +++ b/src/components/ErrorItem.jsx @@ -7,19 +7,13 @@ import remarkReact from 'remark-react'; const parser = remark().use(remarkReact); function ErrorItem(props) { - const lineLabel = props.row >= 0 ? -
On line {props.row + 1}:
: - null; + const lineLabel = props.row >= 0 ?
On line {props.row + 1}:
: null; return (
  • {lineLabel}
    diff --git a/src/components/ErrorList.jsx b/src/components/ErrorList.jsx index 7b53179a8c..5c7c1a45e5 100644 --- a/src/components/ErrorList.jsx +++ b/src/components/ErrorList.jsx @@ -15,26 +15,19 @@ function ErrorList({errors, onErrorClick, language}) { )); - const errorMessage = t( - 'errors.notice', - {count: errors.items.length, language}, - ); + const errorMessage = t('errors.notice', { + count: errors.items.length, + language, + }); return (
    -

    - {errorMessage} -

    -
      - {errorItems} -
    +

    {errorMessage}

    +
      {errorItems}
    ); } diff --git a/src/components/ErrorReport.jsx b/src/components/ErrorReport.jsx index b989a340ba..bc423a02bd 100644 --- a/src/components/ErrorReport.jsx +++ b/src/components/ErrorReport.jsx @@ -25,22 +25,13 @@ function ErrorReport({errors, isValidating, onErrorClick}) { return (
    - - + + - { - isEditing ? - : -
    - {markdownToReact(instructions)} -
    - } +
    + {isEditing ? ( + + ) : ( +
    {markdownToReact(instructions)}
    + )}
    ); } diff --git a/src/components/Modal.jsx b/src/components/Modal.jsx index 63a7ee52f5..887e52bfa0 100644 --- a/src/components/Modal.jsx +++ b/src/components/Modal.jsx @@ -8,13 +8,9 @@ export default function Modal({children, isOpen}) { } return createPortal( - ( -
    -
    - {children} -
    -
    - ), +
    +
    {children}
    +
    , document.getElementById('modals'), ); } diff --git a/src/components/NotificationContainer.jsx b/src/components/NotificationContainer.jsx index 425e32c175..9b6daa5d92 100644 --- a/src/components/NotificationContainer.jsx +++ b/src/components/NotificationContainer.jsx @@ -7,18 +7,13 @@ import {FontAwesomeIcon} from '@fortawesome/react-fontawesome'; export default function NotificationContainer(props) { return (
    {props.children} - +
    diff --git a/src/components/NotificationList.jsx b/src/components/NotificationList.jsx index 3d0a64a4ed..b06c8255fb 100644 --- a/src/components/NotificationList.jsx +++ b/src/components/NotificationList.jsx @@ -36,29 +36,28 @@ export default function NotificationList({ } return ( -
    { - notifications.map((notification) => { +
    + {notifications.map(notification => { const Notification = chooseNotificationComponent(notification); return ( ); - }) - }
    + })} +
    ); } diff --git a/src/components/PopThrobber.jsx b/src/components/PopThrobber.jsx index ace086c8fa..fff08af5e5 100644 --- a/src/components/PopThrobber.jsx +++ b/src/components/PopThrobber.jsx @@ -6,11 +6,9 @@ import Pop from './Pop'; function PopThrobber(props) { return (
    - { - props.message ? -
    {props.message}
    : - null - } + {props.message ? ( +
    {props.message}
    + ) : null}
    ); diff --git a/src/components/Preview.jsx b/src/components/Preview.jsx index e131cccb36..a8f87265e8 100644 --- a/src/components/Preview.jsx +++ b/src/components/Preview.jsx @@ -46,18 +46,11 @@ export default function Preview({ return (
    - + {title} diff --git a/src/components/PreviewFrame.jsx b/src/components/PreviewFrame.jsx index 44162abe77..8554a6f454 100644 --- a/src/components/PreviewFrame.jsx +++ b/src/components/PreviewFrame.jsx @@ -26,7 +26,9 @@ class PreviewFrame extends React.Component { constructor(props) { super(props); - const {compiledProject: {source}} = props; + const { + compiledProject: {source}, + } = props; bindAll(this, '_attachToFrame', '_handleInfiniteLoop'); @@ -56,17 +58,17 @@ class PreviewFrame extends React.Component { } async _evaluateConsoleExpression(key, expression) { - const {hasExpressionStatement} = await retryingFailedImports( - () => import( + const {hasExpressionStatement} = await retryingFailedImports(() => + import( /* webpackChunkName: "mainAsync" */ - '../util/javascript' // eslint-disable-line comma-dangle + '../util/javascript' ), ); // eslint-disable-next-line prefer-reflect this._channel.call({ method: 'evaluateExpression', params: expression, - success: (printedResult) => { + success: printedResult => { this.props.onConsoleValue( key, hasExpressionStatement(expression) ? printedResult : null, @@ -92,8 +94,9 @@ class PreviewFrame extends React.Component { } _runtimeErrorLineOffset() { - const firstSourceLine = this.props.compiledProject.source. - split('\n').indexOf(sourceDelimiter) + 2; + const firstSourceLine = + this.props.compiledProject.source.split('\n').indexOf(sourceDelimiter) + + 2; return firstSourceLine - 1; } diff --git a/src/components/ProjectPreview.jsx b/src/components/ProjectPreview.jsx index 2db1e3210c..e27c84d518 100644 --- a/src/components/ProjectPreview.jsx +++ b/src/components/ProjectPreview.jsx @@ -24,33 +24,29 @@ export default function ProjectPreview({ > {preview.slice(0, MAX_LENGTH)}
    - { - (function showArchived() { - if (isCurrentProject) { - return null; - } - if (project.isArchived) { - return ( -
    - {t('top-bar.project-archived')} -
    - ); - } + {(function showArchived() { + if (isCurrentProject) { + return null; + } + if (project.isArchived) { return ( -
    { - e.stopPropagation(); - onProjectArchived(); - }} - > - +
    + {t('top-bar.project-archived')}
    ); - }()) - } + } + return ( +
    { + e.stopPropagation(); + onProjectArchived(); + }} + > + +
    + ); + })()}
    {project.updatedAt && (
    diff --git a/src/components/ProposedAccountMigration.jsx b/src/components/ProposedAccountMigration.jsx index f846730292..6f100b926b 100644 --- a/src/components/ProposedAccountMigration.jsx +++ b/src/components/ProposedAccountMigration.jsx @@ -4,20 +4,15 @@ import PropTypes from 'prop-types'; import React, {Fragment} from 'react'; import {t} from 'i18next'; -export default function ProposedAccountMigration({ - onDismiss, - onMigrate, -}) { +export default function ProposedAccountMigration({onDismiss, onMigrate}) { return ( - { - map( - t('account-migration.proposal', {returnObjects: true}), - paragraph => ( -

    {paragraph}

    - ), - ) - } + {map( + t('account-migration.proposal', {returnObjects: true}), + paragraph => ( +

    {paragraph}

    + ), + )}
    , ); diff --git a/src/components/TopBar/ProjectPickerButton.jsx b/src/components/TopBar/ProjectPickerButton.jsx index 4cf397be08..e41166f702 100644 --- a/src/components/TopBar/ProjectPickerButton.jsx +++ b/src/components/TopBar/ProjectPickerButton.jsx @@ -8,13 +8,7 @@ import PropTypes from 'prop-types'; export default function ProjectPickerButton({shouldShowSavedIndicator}) { return (
    - + {t('top-bar.load-project')} {t('top-bar.project-saved')} diff --git a/src/components/TopBar/TextSize.jsx b/src/components/TopBar/TextSize.jsx index ca9d91a84c..1430b858d9 100644 --- a/src/components/TopBar/TextSize.jsx +++ b/src/components/TopBar/TextSize.jsx @@ -7,10 +7,7 @@ export default function TextSize({isLarge, onToggle}) { const icon = isLarge ? faSearchMinus : faSearchPlus; return ( -
    +
    ); diff --git a/src/components/TopBar/createMenu.jsx b/src/components/TopBar/createMenu.jsx index fa9b6bff7c..bcb16e0679 100644 --- a/src/components/TopBar/createMenu.jsx +++ b/src/components/TopBar/createMenu.jsx @@ -73,22 +73,19 @@ export default function createMenu({ } const {isOpen, onToggle} = props; - const menu = isOpen ? - ( -
    - {renderItems(props)} -
    - ) : null; + const menu = isOpen ? ( +
    + {renderItems(props)} +
    + ) : null; return (
    @@ -104,11 +101,9 @@ export default function createMenu({ onToggle: PropTypes.func.isRequired, }; - return connect(mapStateToProps, mapDispatchToProps)( - onClickOutside( - Menu, - {handleClickOutside: property('props.onClose')}, - ), - ); + return connect( + mapStateToProps, + mapDispatchToProps, + )(onClickOutside(Menu, {handleClickOutside: property('props.onClose')})); }; } diff --git a/src/components/TopBar/index.jsx b/src/components/TopBar/index.jsx index 2e29888d79..a5abaee67f 100644 --- a/src/components/TopBar/index.jsx +++ b/src/components/TopBar/index.jsx @@ -143,8 +143,10 @@ export default function TopBar({ isOpen={openMenu === 'hamburger'} isUserAuthenticated={isUserAuthenticated} onClick={partial(onClickMenu, 'hamburger')} - onStartEditingInstructions={ - partial(onStartEditingInstructions, currentProjectKey)} + onStartEditingInstructions={partial( + onStartEditingInstructions, + currentProjectKey, + )} onStartGithubLogIn={onStartGithubLogIn} /> diff --git a/src/components/Workspace.jsx b/src/components/Workspace.jsx index 2f227e8333..f68a1c79d9 100644 --- a/src/components/Workspace.jsx +++ b/src/components/Workspace.jsx @@ -47,11 +47,9 @@ export default class Workspace extends React.Component { componentDidMount() { const {onApplicationLoaded} = this.props; - const { - gistId, - snapshotKey, - isExperimental, - } = getQueryParameters(location.search); + const {gistId, snapshotKey, isExperimental} = getQueryParameters( + location.search, + ); const rehydratedProject = rehydrateProject(); setQueryParameters({isExperimental}); @@ -97,24 +95,23 @@ export default class Workspace extends React.Component { } _renderInstructionsBar() { - const currentInstructions = get( - this.props, - ['currentProject', 'instructions'], - ); + const currentInstructions = get(this.props, [ + 'currentProject', + 'instructions', + ]); if (!this.props.isEditingInstructions && !currentInstructions) { return null; } - const isInstructionsHidden = get( - this.props, - ['currentProject', 'hiddenUIComponents'], - ).includes('instructions'); + const isInstructionsHidden = get(this.props, [ + 'currentProject', + 'hiddenUIComponents', + ]).includes('instructions'); return (
    @@ -125,86 +122,74 @@ export default class Workspace extends React.Component { })} icon={faInfoCircle} /> - {!isInstructionsHidden && !this.props.isEditingInstructions && + {!isInstructionsHidden && !this.props.isEditingInstructions && ( { + onClick={e => { e.stopPropagation(); this._handleClickInstructionsEditButton(); }} /> - } + )}
    ); } _renderHiddenLanguages() { - const { - currentProject, - hiddenLanguages, - onComponentToggle, - } = this.props; + const {currentProject, hiddenLanguages, onComponentToggle} = this.props; return ( <> - {hiddenLanguages.map(({language}) => - ( - - ))} + {hiddenLanguages.map(({language}) => ( + + ))} ); } _renderHiddenRightColumnComponents() { - const { - currentProject, - hasErrors, - onComponentToggle, - title, - } = this.props; + const {currentProject, hasErrors, onComponentToggle, title} = this.props; // Errors take over the whole right side of the screen if (hasErrors) { return null; } - return RIGHT_COLUMN_COMPONENTS. - filter(component => ( - includes(currentProject.hiddenUIComponents, component) - )). - map((component) => { - switch (component) { - case 'console': - return ( - - ); - case 'preview': - return ( - - ); - default: - return null; - } - }); + return RIGHT_COLUMN_COMPONENTS.filter(component => + includes(currentProject.hiddenUIComponents, component), + ).map(component => { + switch (component) { + case 'console': + return ( + + ); + case 'preview': + return ( + + ); + default: + return null; + } + }); } _shouldRenderLeftColumn() { @@ -212,14 +197,14 @@ export default class Workspace extends React.Component { } _shouldRenderRightColumn() { - const { - currentProject, - shouldRenderOutput, - } = this.props; - return shouldRenderOutput || some(RIGHT_COLUMN_COMPONENTS, - component => ( - !includes(currentProject.hiddenUIComponents, component) - )); + const {currentProject, shouldRenderOutput} = this.props; + return ( + shouldRenderOutput || + some( + RIGHT_COLUMN_COMPONENTS, + component => !includes(currentProject.hiddenUIComponents, component), + ) + ); } _isEverythingHidden() { @@ -255,7 +240,7 @@ export default class Workspace extends React.Component { const ignorePointerEvents = isDraggingColumnDivider || isAnyTopBarMenuOpen; return (
    - {this._shouldRenderLeftColumn() && + {this._shouldRenderLeftColumn() && ( <>
    - } - {this._shouldRenderRightColumn() && + )} + {this._shouldRenderRightColumn() && ( <>
    - } + )} {this._isEverythingHidden() && this._renderEverythingHidden()}
    ); diff --git a/src/components/notifications/GenericNotificationWithURL.jsx b/src/components/notifications/GenericNotificationWithURL.jsx index 1950443fc4..b223dd02b5 100644 --- a/src/components/notifications/GenericNotificationWithURL.jsx +++ b/src/components/notifications/GenericNotificationWithURL.jsx @@ -4,7 +4,7 @@ import PropTypes from 'prop-types'; export default function GenericNotificationWithURL({text, url, linkText}) { return ( - {text} {' '} + {text}{' '}
    {linkText} diff --git a/src/components/notifications/ProjectExportNotification.jsx b/src/components/notifications/ProjectExportNotification.jsx index e12beb5f08..b432cfff9e 100644 --- a/src/components/notifications/ProjectExportNotification.jsx +++ b/src/components/notifications/ProjectExportNotification.jsx @@ -12,11 +12,7 @@ export default function ProjectExportNotification({metadata}) { const text = t(`notifications.${exportType}-export-complete`); return ( - + ); } diff --git a/src/components/notifications/SnapshotNotification.jsx b/src/components/notifications/SnapshotNotification.jsx index 585b75749f..f906da4096 100644 --- a/src/components/notifications/SnapshotNotification.jsx +++ b/src/components/notifications/SnapshotNotification.jsx @@ -9,18 +9,12 @@ import {t} from 'i18next'; import {createSnapshotUrl} from '../../util/exportUrls'; -export default function SnapshotNotification({ - metadata, - onUpdateMetadata, -}) { +export default function SnapshotNotification({metadata, onUpdateMetadata}) { const uri = createSnapshotUrl(metadata.get('snapshotKey')); let checkmark; if (metadata.get('isCopied')) { - checkmark = [ - ' ', - , - ]; + checkmark = [' ', ]; } return ( @@ -28,13 +22,9 @@ export default function SnapshotNotification({ {t('notifications.snapshot-created')}{' '} - - {t('notifications.click-to-copy')} - + {t('notifications.click-to-copy')} {checkmark} diff --git a/src/config.js b/src/config.js index 17f560d6ce..5204df2003 100644 --- a/src/config.js +++ b/src/config.js @@ -3,7 +3,7 @@ /* eslint-disable import/no-commonjs */ module.exports = { - nodeEnv: (process.env.NODE_ENV || 'development'), + nodeEnv: process.env.NODE_ENV || 'development', logReduxActions: () => process.env.LOG_REDUX_ACTIONS === 'true', warnOnDroppedErrors: process.env.WARN_ON_DROPPED_ERRORS === 'true', diff --git a/src/config/libraryAssets.js b/src/config/libraryAssets.js index d7ded01579..3f7b02787e 100644 --- a/src/config/libraryAssets.js +++ b/src/config/libraryAssets.js @@ -3,10 +3,8 @@ import JQUERY from '../../node_modules/jquery/dist/jquery.min.js'; import LODASH from '../../bower_components/lodash/dist/lodash.min.js'; import MUSTACHE from '../../bower_components/mustache.js/mustache.js'; -import BOOTSTRAP_CSS from - '../../bower_components/bootstrap/dist/css/bootstrap.min.css'; -import BOOTSTRAP_JS from - '../../bower_components/bootstrap/dist/js/bootstrap.min.js'; +import BOOTSTRAP_CSS from '../../bower_components/bootstrap/dist/css/bootstrap.min.css'; +import BOOTSTRAP_JS from '../../bower_components/bootstrap/dist/js/bootstrap.min.js'; import P5 from '../../node_modules/p5/lib/p5.min.js'; export const jquery = {javascript: JQUERY}; diff --git a/src/containers/AssignmentCreator.js b/src/containers/AssignmentCreator.js index c484743c8f..2590aa3ffd 100644 --- a/src/containers/AssignmentCreator.js +++ b/src/containers/AssignmentCreator.js @@ -2,10 +2,7 @@ import {connect} from 'react-redux'; import {AssignmentState} from '../enums'; -import { - closeAssignmentCreator, - createAssignment, -} from '../actions'; +import {closeAssignmentCreator, createAssignment} from '../actions'; import { getCourses, isAssignmentCreatorOpen, @@ -17,8 +14,10 @@ import { import AssignmentCreator from '../components/AssignmentCreator'; -const areCoursesLoaded = - makeIsRemoteCollectionFullyLoaded(['googleClassroom', 'courses']); +const areCoursesLoaded = makeIsRemoteCollectionFullyLoaded([ + 'googleClassroom', + 'courses', +]); function mapStateToProps(state) { return { @@ -36,21 +35,17 @@ function mapDispatchToProps(dispatch) { onAssignAssignment(data) { const selectedCourseId = data.get('course'); const dueDate = data.get('date').parsedDate; - dispatch(createAssignment( - selectedCourseId, - dueDate, - AssignmentState.PUBLISHED, - )); + dispatch( + createAssignment(selectedCourseId, dueDate, AssignmentState.PUBLISHED), + ); }, onDraftAssignment(data) { const selectedCourseId = data.get('course'); const dueDate = data.get('date').parsedDate; - dispatch(createAssignment( - selectedCourseId, - dueDate, - AssignmentState.DRAFT, - )); + dispatch( + createAssignment(selectedCourseId, dueDate, AssignmentState.DRAFT), + ); }, onCloseAssignmentCreator() { diff --git a/src/containers/AssignmentCreatorForm.js b/src/containers/AssignmentCreatorForm.js index f1fef71f83..e390d8b20b 100644 --- a/src/containers/AssignmentCreatorForm.js +++ b/src/containers/AssignmentCreatorForm.js @@ -4,8 +4,7 @@ import isEmpty from 'lodash-es/isEmpty'; import isNil from 'lodash-es/isNil'; import get from 'lodash-es/get'; -import AssignmentCreatorFormComponent - from '../components/AssignmentCreatorForm'; +import AssignmentCreatorFormComponent from '../components/AssignmentCreatorForm'; function validate(values) { const errors = {}; diff --git a/src/containers/ErrorReport.js b/src/containers/ErrorReport.js index db20b67697..90e9d2c10f 100644 --- a/src/containers/ErrorReport.js +++ b/src/containers/ErrorReport.js @@ -12,7 +12,8 @@ import { function mapStateToProps(state) { return { errors: getErrors(state), - isValidating: isCurrentlyValidating(state) || + isValidating: + isCurrentlyValidating(state) || (isUserTyping(state) && !isCurrentProjectSyntacticallyValid(state)), }; } diff --git a/src/containers/Instructions.js b/src/containers/Instructions.js index cdd3acaf8b..e7ef46e0a3 100644 --- a/src/containers/Instructions.js +++ b/src/containers/Instructions.js @@ -7,10 +7,7 @@ import { getHiddenUIComponents, isEditingInstructions, } from '../selectors'; -import { - cancelEditingInstructions, - updateProjectInstructions, -} from '../actions'; +import {cancelEditingInstructions, updateProjectInstructions} from '../actions'; function mapStateToProps(state) { return { diff --git a/src/containers/Preview.js b/src/containers/Preview.js index d0b22cd910..e422e161bc 100644 --- a/src/containers/Preview.js +++ b/src/containers/Preview.js @@ -28,10 +28,8 @@ function mapStateToProps(state) { consoleEntries: getConsoleHistory(state), currentProjectKey: getCurrentProjectKey(state), isOpen: !getHiddenUIComponents(state).includes('preview'), - showingErrors: ( - !isUserTyping(state) && - !isCurrentProjectSyntacticallyValid(state) - ), + showingErrors: + !isUserTyping(state) && !isCurrentProjectSyntacticallyValid(state), title: getCurrentProjectPreviewTitle(state), }; } diff --git a/src/containers/ProjectPreview.js b/src/containers/ProjectPreview.js index 9d8e55e0a4..a5da8c4d2d 100644 --- a/src/containers/ProjectPreview.js +++ b/src/containers/ProjectPreview.js @@ -1,10 +1,7 @@ import {connect} from 'react-redux'; import ProjectPreview from '../components/ProjectPreview'; -import { - archiveProject, - changeCurrentProject, -} from '../actions'; +import {archiveProject, changeCurrentProject} from '../actions'; import { makeGetProjectPreview, getCurrentProjectKey, diff --git a/src/containers/TopBar.js b/src/containers/TopBar.js index cb5ff10149..df0d87245e 100644 --- a/src/containers/TopBar.js +++ b/src/containers/TopBar.js @@ -156,7 +156,6 @@ function mapDispatchToProps(dispatch) { onToggleViewArchived() { dispatch(toggleArchivedView()); }, - }; } diff --git a/src/containers/Workspace.js b/src/containers/Workspace.js index 6882d705da..77f764d1d3 100644 --- a/src/containers/Workspace.js +++ b/src/containers/Workspace.js @@ -33,10 +33,11 @@ function mapStateToProps(state) { RIGHT_COLUMN_COMPONENTS, component => hiddenUIComponents.includes(component), ); - const shouldRenderOutput = !areAllRightColumnComponentsCollapsed || + const shouldRenderOutput = + !areAllRightColumnComponentsCollapsed || (!isCurrentProjectValid && - !isCurrentProjectValidating && - !isUserTyping(state)); + !isCurrentProjectValidating && + !isUserTyping(state)); return { currentProject: getCurrentProject(state), hasErrors: !isCurrentProjectValid, diff --git a/src/createApplicationStore.js b/src/createApplicationStore.js index 56ee3f2fcb..4e91cd1f73 100644 --- a/src/createApplicationStore.js +++ b/src/createApplicationStore.js @@ -35,7 +35,10 @@ export default function createApplicationStore() { const store = createStore( reducers, - compose(sagaEnhancer, logicEnhancer), + compose( + sagaEnhancer, + logicEnhancer, + ), ); sagaMiddleware.run(rootSaga); diff --git a/src/css/application.css b/src/css/application.css index fb6a86aa38..85a5388d64 100644 --- a/src/css/application.css +++ b/src/css/application.css @@ -201,7 +201,10 @@ body { border-radius: var(--size-rounded-corners); box-shadow: 0 0 20px rgba(0, 0, 0, 0.25); position: absolute; - top: calc(var(--size-top-bar-menu-button) + (var(--size-top-bar) - var(--size-top-bar-menu-button)) / 2); + top: calc( + var(--size-top-bar-menu-button) + + (var(--size-top-bar) - var(--size-top-bar-menu-button)) / 2 + ); min-width: 100%; max-height: 50vh; max-width: 30em; diff --git a/src/enums/index.js b/src/enums/index.js index 661c338fc0..22404355d2 100644 --- a/src/enums/index.js +++ b/src/enums/index.js @@ -1,10 +1,9 @@ import Enum from 'enum'; -export const LoginState = new Enum([ - 'UNKNOWN', - 'ANONYMOUS', - 'AUTHENTICATED', -], 'LoginState'); +export const LoginState = new Enum( + ['UNKNOWN', 'ANONYMOUS', 'AUTHENTICATED'], + 'LoginState', +); export const AccountMigrationState = new Enum([ 'PROPOSED', @@ -14,8 +13,4 @@ export const AccountMigrationState = new Enum([ 'ERROR', ]); -export const AssignmentState = new Enum([ - 'PUBLISHED', - 'DRAFT', - 'ASSIGNMENT', -]); +export const AssignmentState = new Enum(['PUBLISHED', 'DRAFT', 'ASSIGNMENT']); diff --git a/src/higherOrderComponents/resizableFlex/calculateFlexGrowAfterDrag.js b/src/higherOrderComponents/resizableFlex/calculateFlexGrowAfterDrag.js index 9fc696fe69..9490815940 100644 --- a/src/higherOrderComponents/resizableFlex/calculateFlexGrowAfterDrag.js +++ b/src/higherOrderComponents/resizableFlex/calculateFlexGrowAfterDrag.js @@ -15,14 +15,14 @@ export default function calculateFlexGrowAfterDrag( return [currentBeforeFlexGrow, currentAfterFlexGrow]; } - const desiredAfterSize = currentBeforeSize + currentAfterSize - - desiredBeforeSize; + const desiredAfterSize = + currentBeforeSize + currentAfterSize - desiredBeforeSize; if (desiredAfterSize < afterInitialMainSize) { return [currentBeforeFlexGrow, currentAfterFlexGrow]; } - const desiredRatio = desiredBeforeSize / - (currentBeforeSize + currentAfterSize); + const desiredRatio = + desiredBeforeSize / (currentBeforeSize + currentAfterSize); const totalFlexGrow = currentBeforeFlexGrow + currentAfterFlexGrow; const desiredBeforeFlexGrow = totalFlexGrow * desiredRatio; diff --git a/src/higherOrderComponents/resizableFlex/index.js b/src/higherOrderComponents/resizableFlex/index.js index 8e8a2b8fe6..a777afe3e0 100644 --- a/src/higherOrderComponents/resizableFlex/index.js +++ b/src/higherOrderComponents/resizableFlex/index.js @@ -27,7 +27,7 @@ export default function resizableFlex(size) { const getResizableFlexGrow = makeGetResizableFlexGrow(instanceId); return connectAdvanced( - (dispatch) => { + dispatch => { const regions = times(size, () => ({current: null})); const initialMainSizes = times(size, () => null); @@ -36,73 +36,63 @@ export default function resizableFlex(size) { onResizableFlexDividerDrag(beforeIndex, event, payload) { const afterIndex = findIndex(regions, 'current', beforeIndex + 1); - const [{current: before}, {current: after}] = - at(regions, [beforeIndex, afterIndex]); + const [{current: before}, {current: after}] = at(regions, [ + beforeIndex, + afterIndex, + ]); - const {getCurrentSize, getDesiredSize} = - directionAdapterFor(before); + const {getCurrentSize, getDesiredSize} = directionAdapterFor(before); - const [desiredBeforeFlexGrow, desiredAfterFlexGrow] = - calculateFlexGrowAfterDrag( - { - currentFlexGrow: Number( - getComputedStyle(before)['flex-grow'], - ), - currentSize: getCurrentSize(before), - desiredSize: getDesiredSize(before, payload), - initialMainSize: initialMainSizes[beforeIndex], - }, - { - currentFlexGrow: Number( - getComputedStyle(after)['flex-grow'], - ), - currentSize: getCurrentSize(after), - initialMainSize: initialMainSizes[afterIndex], - }, - ); + const [ + desiredBeforeFlexGrow, + desiredAfterFlexGrow, + ] = calculateFlexGrowAfterDrag( + { + currentFlexGrow: Number(getComputedStyle(before)['flex-grow']), + currentSize: getCurrentSize(before), + desiredSize: getDesiredSize(before, payload), + initialMainSize: initialMainSizes[beforeIndex], + }, + { + currentFlexGrow: Number(getComputedStyle(after)['flex-grow']), + currentSize: getCurrentSize(after), + initialMainSize: initialMainSizes[afterIndex], + }, + ); - dispatch(updateResizableFlex( - instanceId, - [ + dispatch( + updateResizableFlex(instanceId, [ {index: beforeIndex, flexGrow: desiredBeforeFlexGrow}, {index: afterIndex, flexGrow: desiredAfterFlexGrow}, - ], - )); + ]), + ); }, - resizableFlexRefs: map( - regions, - (region, index) => (element) => { - region.current = element; - if (isNull(element)) { - initialMainSizes[index] = null; - return; - } + resizableFlexRefs: map(regions, (region, index) => element => { + region.current = element; + if (isNull(element)) { + initialMainSizes[index] = null; + return; + } - const flexGrowWas = element.style.flexGrow; - const flexShrinkWas = element.style.flexShrink; - element.style.flexGrow = element.style.flexShrink = '0'; - initialMainSizes[index] = directionAdapterFor(element). - getCurrentSize(element); - element.style.flexGrow = flexGrowWas; - element.style.flexShrink = flexShrinkWas; - }, - ), + const flexGrowWas = element.style.flexGrow; + const flexShrinkWas = element.style.flexShrink; + element.style.flexGrow = element.style.flexShrink = '0'; + initialMainSizes[index] = directionAdapterFor(element).getCurrentSize( + element, + ); + element.style.flexGrow = flexGrowWas; + element.style.flexShrink = flexShrinkWas; + }), }; return createSelector( [ getResizableFlexGrow, - defaultMemoize( - (_state, ownProps) => ownProps, - shallowequal, - ), + defaultMemoize((_state, ownProps) => ownProps, shallowequal), ], - (resizableFlexGrow, ownProps) => merge( - {resizableFlexGrow}, - ownProps, - stateIndependentFunctions, - ), + (resizableFlexGrow, ownProps) => + merge({resizableFlexGrow}, ownProps, stateIndependentFunctions), ); }, { diff --git a/src/higherOrderComponents/resizableFlex/sham.js b/src/higherOrderComponents/resizableFlex/sham.js index 3115877abb..a83ff4a619 100644 --- a/src/higherOrderComponents/resizableFlex/sham.js +++ b/src/higherOrderComponents/resizableFlex/sham.js @@ -11,12 +11,12 @@ export default function resizableFlex(size) { onResizableFlexDividerDrag: noop, }; - return (Component) => { + return Component => { function WrappedComponent(ownProps) { return ; } - WrappedComponent.displayName = - `ResizableFlex.sham(${Component.displayName || Component.name}`; + WrappedComponent.displayName = `ResizableFlex.sham(${Component.displayName || + Component.name}`; return WrappedComponent; }; } diff --git a/src/html/index.html b/src/html/index.html index 9156d982a9..8643510abd 100644 --- a/src/html/index.html +++ b/src/html/index.html @@ -1,17 +1,27 @@ - + Popcode | HTML, CSS, and JavaScript editor for students - - - - - - - - - - + + + + + + + + + +
    diff --git a/src/logic/__tests__/linkGithubIdentityTest.js b/src/logic/__tests__/linkGithubIdentityTest.js index 5646a2db95..7564b02dd0 100644 --- a/src/logic/__tests__/linkGithubIdentityTest.js +++ b/src/logic/__tests__/linkGithubIdentityTest.js @@ -1,8 +1,5 @@ import linkGithubIdentity from '../linkGithubIdentity'; -import { - linkGithub, - saveCredentialForCurrentUser, -} from '../../clients/firebase'; +import {linkGithub, saveCredentialForCurrentUser} from '../../clients/firebase'; import {getProfileForAuthenticatedUser} from '../../clients/github'; import {bugsnagClient} from '../../util/bugsnag'; @@ -20,7 +17,7 @@ jest.mock('../../clients/github.js'); jest.mock('../../util/bugsnag.js'); describe('linkGithubIdentity', () => { - test('success', async() => { + test('success', async () => { const mockCredential = credentialFactory.build(); const mockUser = userFactory.build(); @@ -44,7 +41,7 @@ describe('linkGithubIdentity', () => { expect(user).toEqual(mockUser); }); - test('credential already in use', async() => { + test('credential already in use', async () => { const error = credentialInUseErrorFactory.build(); const githubProfile = githubProfileFactory.build(); @@ -54,10 +51,7 @@ describe('linkGithubIdentity', () => { const { type, payload: { - credential: { - providerId, - accessToken, - }, + credential: {providerId, accessToken}, }, } = await linkGithubIdentity.process(); expect(linkGithub).toHaveBeenCalledWith(); @@ -69,7 +63,7 @@ describe('linkGithubIdentity', () => { expect(accessToken).toBe(error.credential.accessToken); }); - test('other error', async() => { + test('other error', async () => { const otherError = firebaseErrorFactory.build(); linkGithub.mockRejectedValue(otherError); diff --git a/src/logic/__tests__/unlinkGithubIdentity.test.js b/src/logic/__tests__/unlinkGithubIdentity.test.js index 1e596f824d..ff9ce6f185 100644 --- a/src/logic/__tests__/unlinkGithubIdentity.test.js +++ b/src/logic/__tests__/unlinkGithubIdentity.test.js @@ -4,8 +4,11 @@ import {unlinkGithub} from '../../clients/firebase'; jest.mock('../../clients/firebase.js'); -test('should unlink Github Identity', async() => { - const {type, payload: {providerId}} = await unlinkGithubIdentity.process(); +test('should unlink Github Identity', async () => { + const { + type, + payload: {providerId}, + } = await unlinkGithubIdentity.process(); expect(unlinkGithub).toHaveBeenCalledWith(); expect(type).toBe('IDENTITY_UNLINKED'); expect(providerId).toBe('github.com'); diff --git a/src/logic/index.js b/src/logic/index.js index 143b19eaff..bba13a43f0 100644 --- a/src/logic/index.js +++ b/src/logic/index.js @@ -1,7 +1,4 @@ import linkGithubIdentity from './linkGithubIdentity'; import unlinkGithubIdentity from './unlinkGithubIdentity'; -export default [ - linkGithubIdentity, - unlinkGithubIdentity, -]; +export default [linkGithubIdentity, unlinkGithubIdentity]; diff --git a/src/logic/linkGithubIdentity.js b/src/logic/linkGithubIdentity.js index a421da7a9c..fe63539f72 100644 --- a/src/logic/linkGithubIdentity.js +++ b/src/logic/linkGithubIdentity.js @@ -1,9 +1,6 @@ import {createLogic} from 'redux-logic'; -import { - linkGithub, - saveCredentialForCurrentUser, -} from '../clients/firebase'; +import {linkGithub, saveCredentialForCurrentUser} from '../clients/firebase'; import { accountMigrationNeeded, identityLinked, diff --git a/src/patches/stylelint/lib/requireRule.js b/src/patches/stylelint/lib/requireRule.js index 6d00644f83..7f333c58e3 100644 --- a/src/patches/stylelint/lib/requireRule.js +++ b/src/patches/stylelint/lib/requireRule.js @@ -1,8 +1,7 @@ /* eslint-env commonjs */ /* eslint-disable import/no-commonjs */ -const declarationBlockTrailingSemicolon = - require('stylelint/lib/rules/declaration-block-trailing-semicolon'); +const declarationBlockTrailingSemicolon = require('stylelint/lib/rules/declaration-block-trailing-semicolon'); module.exports = function requireRule(ruleName) { if (ruleName === 'declaration-block-trailing-semicolon') { diff --git a/src/preview.js b/src/preview.js index 08ec4e543f..6be4d662aa 100644 --- a/src/preview.js +++ b/src/preview.js @@ -1,6 +1,5 @@ import handleErrors from './previewSupport/handleErrors'; -import handleConsoleExpressions - from './previewSupport/handleConsoleExpressions'; +import handleConsoleExpressions from './previewSupport/handleConsoleExpressions'; import handleConsoleLogs from './previewSupport/handleConsoleLogs'; import overrideAlert from './previewSupport/overrideAlert'; diff --git a/src/previewSupport/handleConsoleExpressions.js b/src/previewSupport/handleConsoleExpressions.js index 9322773bf1..bacf1efa31 100644 --- a/src/previewSupport/handleConsoleExpressions.js +++ b/src/previewSupport/handleConsoleExpressions.js @@ -2,13 +2,12 @@ import channel from './channel'; import createScopedEvaluationChain from './createScopedEvaluationChain'; import prettyPrint from './prettyPrint'; -let evalNext = createScopedEvaluationChain((next) => { +let evalNext = createScopedEvaluationChain(next => { evalNext = next; }); export default function handleConsoleExpressions() { - channel.bind( - 'evaluateExpression', - (_trans, expression) => prettyPrint(evalNext(expression)), + channel.bind('evaluateExpression', (_trans, expression) => + prettyPrint(evalNext(expression)), ); } diff --git a/src/previewSupport/handleConsoleLogs.js b/src/previewSupport/handleConsoleLogs.js index 29da7cf69e..93b502f86a 100644 --- a/src/previewSupport/handleConsoleLogs.js +++ b/src/previewSupport/handleConsoleLogs.js @@ -13,7 +13,7 @@ function notifyChannel(args) { } export default function handleConsoleLogs() { - consoleFunctions.forEach((functionName) => { + consoleFunctions.forEach(functionName => { let browserFunction; // eslint-disable-next-line no-console if (console[functionName]) { diff --git a/src/previewSupport/overrideAlert.js b/src/previewSupport/overrideAlert.js index 18b0f15047..06fc00b4c5 100644 --- a/src/previewSupport/overrideAlert.js +++ b/src/previewSupport/overrideAlert.js @@ -3,7 +3,7 @@ import swal from 'sweetalert2'; export default function overrideAlert() { Object.defineProperties(window, { alert: { - value: (message) => { + value: message => { swal(String(message)); }, configurable: true, diff --git a/src/records/AccountMigration.js b/src/records/AccountMigration.js index 4343a5b4c1..ea9eea45ae 100644 --- a/src/records/AccountMigration.js +++ b/src/records/AccountMigration.js @@ -2,8 +2,11 @@ import {Record} from 'immutable'; import {AccountMigrationState} from '../enums'; -export default Record({ - state: AccountMigrationState.PROPOSED, - userAccountToMerge: null, - firebaseCredential: null, -}, 'AccountMigration'); +export default Record( + { + state: AccountMigrationState.PROPOSED, + userAccountToMerge: null, + firebaseCredential: null, + }, + 'AccountMigration', +); diff --git a/src/records/CompiledProject.js b/src/records/CompiledProject.js index 5f7eb20069..ed8cc6f805 100644 --- a/src/records/CompiledProject.js +++ b/src/records/CompiledProject.js @@ -1,7 +1,10 @@ import {Record} from 'immutable'; -export default Record({ - source: '', - compiledProjectKey: null, - title: '', -}, 'CompiledProject'); +export default Record( + { + source: '', + compiledProjectKey: null, + title: '', + }, + 'CompiledProject', +); diff --git a/src/records/ConsoleEntry.js b/src/records/ConsoleEntry.js index 85c64a702d..112cdb0361 100644 --- a/src/records/ConsoleEntry.js +++ b/src/records/ConsoleEntry.js @@ -1,8 +1,11 @@ import {Record} from 'immutable'; -export default Record({ - expression: null, - value: null, - error: null, - evaluatedByCompiledProjectKey: null, -}, 'ConsoleEntry'); +export default Record( + { + expression: null, + value: null, + error: null, + evaluatedByCompiledProjectKey: null, + }, + 'ConsoleEntry', +); diff --git a/src/records/ConsoleError.js b/src/records/ConsoleError.js index bdfb4ab668..098eed064e 100644 --- a/src/records/ConsoleError.js +++ b/src/records/ConsoleError.js @@ -1,6 +1,9 @@ import {Record} from 'immutable'; -export default Record({ - name: '', - message: '', -}, 'ConsoleError'); +export default Record( + { + name: '', + message: '', + }, + 'ConsoleError', +); diff --git a/src/records/ConsoleState.js b/src/records/ConsoleState.js index 7786b00d48..1028d4e501 100644 --- a/src/records/ConsoleState.js +++ b/src/records/ConsoleState.js @@ -1,8 +1,11 @@ import {Record, OrderedMap} from 'immutable'; -export default Record({ - history: new OrderedMap(), - historyEntryIndex: 0, - nextConsoleEntry: null, - currentInputValue: '', -}, 'ConsoleState'); +export default Record( + { + history: new OrderedMap(), + historyEntryIndex: 0, + nextConsoleEntry: null, + currentInputValue: '', + }, + 'ConsoleState', +); diff --git a/src/records/Course.js b/src/records/Course.js index aac2667d04..45784ac969 100644 --- a/src/records/Course.js +++ b/src/records/Course.js @@ -1,9 +1,12 @@ import {Record} from 'immutable'; -export default Record({ - id: null, - name: null, - section: null, - ownerId: null, - alternateLink: null, -}, 'Course'); +export default Record( + { + id: null, + name: null, + section: null, + ownerId: null, + alternateLink: null, + }, + 'Course', +); diff --git a/src/records/EditorLocation.js b/src/records/EditorLocation.js index 2f2628820a..fa63cdc54c 100644 --- a/src/records/EditorLocation.js +++ b/src/records/EditorLocation.js @@ -1,7 +1,10 @@ import {Record} from 'immutable'; -export default Record({ - component: null, - line: 0, - column: 0, -}, 'EditorLocation'); +export default Record( + { + component: null, + line: 0, + column: 0, + }, + 'EditorLocation', +); diff --git a/src/records/Error.js b/src/records/Error.js index e731f60020..7faec55d0a 100644 --- a/src/records/Error.js +++ b/src/records/Error.js @@ -1,15 +1,18 @@ import {List, Map, Record} from 'immutable'; -export default class Error extends Record({ - row: null, - column: null, - reason: null, - payload: new Map(), - suppresses: new List(), - text: null, - raw: null, - type: 'error', -}, 'Error') { +export default class Error extends Record( + { + row: null, + column: null, + reason: null, + payload: new Map(), + suppresses: new List(), + text: null, + raw: null, + type: 'error', + }, + 'Error', +) { static fromJS(js) { return new this( Object.assign({}, js, { diff --git a/src/records/ErrorList.js b/src/records/ErrorList.js index f999ea7356..5d6d967e32 100644 --- a/src/records/ErrorList.js +++ b/src/records/ErrorList.js @@ -1,6 +1,9 @@ import {List, Record} from 'immutable'; -export default Record({ - items: new List(), - state: 'passed', -}, 'ErrorList'); +export default Record( + { + items: new List(), + state: 'passed', + }, + 'ErrorList', +); diff --git a/src/records/ErrorReport.js b/src/records/ErrorReport.js index 38d281b08e..3a2d934340 100644 --- a/src/records/ErrorReport.js +++ b/src/records/ErrorReport.js @@ -4,8 +4,11 @@ import ErrorList from './ErrorList'; const defaultErrorList = new ErrorList(); -export default Record({ - html: defaultErrorList, - css: defaultErrorList, - javascript: defaultErrorList, -}, 'ErrorReport'); +export default Record( + { + html: defaultErrorList, + css: defaultErrorList, + javascript: defaultErrorList, + }, + 'ErrorReport', +); diff --git a/src/records/FormDate.js b/src/records/FormDate.js index 6631a80218..23596464a7 100644 --- a/src/records/FormDate.js +++ b/src/records/FormDate.js @@ -1,6 +1,9 @@ import {Record} from 'immutable'; -export default Record({ - string: null, - parsedDate: null, -}, 'FormDate'); +export default Record( + { + string: null, + parsedDate: null, + }, + 'FormDate', +); diff --git a/src/records/GoogleClassroom.js b/src/records/GoogleClassroom.js index c2e6bbefc4..d00a1f51f8 100644 --- a/src/records/GoogleClassroom.js +++ b/src/records/GoogleClassroom.js @@ -2,6 +2,9 @@ import {Record} from 'immutable'; import RemoteColection from './RemoteCollection'; -export default Record({ - courses: new RemoteColection(), -}, 'GoogleClassroom'); +export default Record( + { + courses: new RemoteColection(), + }, + 'GoogleClassroom', +); diff --git a/src/records/Notification.js b/src/records/Notification.js index d888b4ec20..f24482f202 100644 --- a/src/records/Notification.js +++ b/src/records/Notification.js @@ -1,7 +1,10 @@ import {Map, Record} from 'immutable'; -export default Record({ - type: null, - severity: 'notice', - metadata: new Map(), -}, 'Notification'); +export default Record( + { + type: null, + severity: 'notice', + metadata: new Map(), + }, + 'Notification', +); diff --git a/src/records/RemoteCollection.js b/src/records/RemoteCollection.js index 5b2a883c1d..c8f06d45ef 100644 --- a/src/records/RemoteCollection.js +++ b/src/records/RemoteCollection.js @@ -1,6 +1,9 @@ import {Record, Map} from 'immutable'; -export default Record({ - items: new Map(), - isFullyLoaded: false, -}, 'RemoteCollection'); +export default Record( + { + items: new Map(), + isFullyLoaded: false, + }, + 'RemoteCollection', +); diff --git a/src/records/UiState.js b/src/records/UiState.js index e0b3ee1470..8a0b362397 100644 --- a/src/records/UiState.js +++ b/src/records/UiState.js @@ -1,15 +1,18 @@ import {Record, Map} from 'immutable'; -export default Record({ - isAssignmentCreatorOpen: false, - isDraggingColumnDivider: false, - isEditingInstructions: false, - isExperimental: false, - isTextSizeLarge: false, - isTyping: false, - notifications: new Map(), - openTopBarMenu: null, - requestedFocusedLine: null, - saveIndicatorShown: false, - archivedViewOpen: false, -}, 'UiState'); +export default Record( + { + isAssignmentCreatorOpen: false, + isDraggingColumnDivider: false, + isEditingInstructions: false, + isExperimental: false, + isTextSizeLarge: false, + isTyping: false, + notifications: new Map(), + openTopBarMenu: null, + requestedFocusedLine: null, + saveIndicatorShown: false, + archivedViewOpen: false, + }, + 'UiState', +); diff --git a/src/records/User.js b/src/records/User.js index 552a6d76ac..885918fd15 100644 --- a/src/records/User.js +++ b/src/records/User.js @@ -2,8 +2,11 @@ import {Record} from 'immutable'; import {LoginState} from '../enums'; -export default Record({ - loginState: LoginState.UNKNOWN, - account: null, - currentMigration: null, -}, 'User'); +export default Record( + { + loginState: LoginState.UNKNOWN, + account: null, + currentMigration: null, + }, + 'User', +); diff --git a/src/records/UserAccount.js b/src/records/UserAccount.js index 35bdb5d978..f1db73c49d 100644 --- a/src/records/UserAccount.js +++ b/src/records/UserAccount.js @@ -1,8 +1,11 @@ import {Map, Record} from 'immutable'; -export default Record({ - id: null, - displayName: null, - avatarUrl: null, - identityProviders: new Map(), -}, 'UserAccount'); +export default Record( + { + id: null, + displayName: null, + avatarUrl: null, + identityProviders: new Map(), + }, + 'UserAccount', +); diff --git a/src/records/UserIdentityProvider.js b/src/records/UserIdentityProvider.js index c568a91568..2aa72ee023 100644 --- a/src/records/UserIdentityProvider.js +++ b/src/records/UserIdentityProvider.js @@ -1,7 +1,10 @@ import {Record} from 'immutable'; -export default Record({ - accessToken: null, - avatarUrl: null, - displayName: null, -}, 'UserIdentityProvider'); +export default Record( + { + accessToken: null, + avatarUrl: null, + displayName: null, + }, + 'UserIdentityProvider', +); diff --git a/src/reducers/__tests__/console.test.jsx b/src/reducers/__tests__/console.test.jsx index 6405615814..c81cb4f8f3 100644 --- a/src/reducers/__tests__/console.test.jsx +++ b/src/reducers/__tests__/console.test.jsx @@ -20,9 +20,7 @@ import {consoleErrorFactory} from '@factories/validations/errors'; test('evaluateConsoleEntry adds entry to history', () => { const expression = '1 + 1'; const key = '123'; - const {history} = applyActions( - evaluateConsoleEntry(expression, key), - ); + const {history} = applyActions(evaluateConsoleEntry(expression, key)); expect(history.size).toBe(1); expect(history.get(key)).toMatchObject({expression}); }); @@ -157,9 +155,5 @@ describe('nextConsoleHistory', () => { }); function applyActions(...actions) { - return reduce( - actions, - (state, action) => reducer(state, action), - undefined, - ); + return reduce(actions, (state, action) => reducer(state, action), undefined); } diff --git a/src/reducers/clients.js b/src/reducers/clients.js index c12629fb91..1278e3012c 100644 --- a/src/reducers/clients.js +++ b/src/reducers/clients.js @@ -45,17 +45,11 @@ export default function clients(stateIn, action) { return state.setIn(['gapi', 'ready'], true); case 'CREATE_ASSIGNMENT': - return state.setIn( - ['exportingAssignment'], - true, - ); + return state.setIn(['exportingAssignment'], true); case 'ASSIGNMENT_CREATED': case 'ASSIGNMENT_NOT_CREATED': - return state.setIn( - ['exportingAssignment'], - false, - ); + return state.setIn(['exportingAssignment'], false); } return state; diff --git a/src/reducers/compiledProjects.js b/src/reducers/compiledProjects.js index ad221407a3..56f08e9912 100644 --- a/src/reducers/compiledProjects.js +++ b/src/reducers/compiledProjects.js @@ -32,21 +32,25 @@ export default function compiledProjects(stateIn, action) { const {source, title} = state.last(); return trimRight( - state.push(new CompiledProject({ - source, - title, - compiledProjectKey: action.payload.timestamp, - })), + state.push( + new CompiledProject({ + source, + title, + compiledProjectKey: action.payload.timestamp, + }), + ), ); } case 'PROJECT_COMPILED': return trimRight( - state.push(new CompiledProject({ - source: action.payload.source, - title: action.payload.title, - compiledProjectKey: action.meta.timestamp, - })), + state.push( + new CompiledProject({ + source: action.payload.source, + title: action.payload.title, + compiledProjectKey: action.meta.timestamp, + }), + ), 2, ); diff --git a/src/reducers/console.js b/src/reducers/console.js index 95feab2d3a..491e1d8fd6 100644 --- a/src/reducers/console.js +++ b/src/reducers/console.js @@ -3,7 +3,6 @@ import inRange from 'lodash-es/inRange'; import isNil from 'lodash-es/isNil'; import {handleActions} from 'redux-actions'; - import {ConsoleState, ConsoleEntry, Error} from '../records'; import { @@ -20,11 +19,12 @@ import { const initialState = new ConsoleState(); function updateConsoleForHistoryIndex(state, index) { - const expressionHistory = state.history.toList(). - map(entry => entry.expression). - filter(expression => expression !== null). - concat(state.nextConsoleEntry). - reverse(); + const expressionHistory = state.history + .toList() + .map(entry => entry.expression) + .filter(expression => expression !== null) + .concat(state.nextConsoleEntry) + .reverse(); if (!inRange(index, expressionHistory.size)) { return state; @@ -32,9 +32,9 @@ function updateConsoleForHistoryIndex(state, index) { const expression = expressionHistory.get(index); - const nextState = state. - set('historyEntryIndex', index). - set('currentInputValue', expression); + const nextState = state + .set('historyEntryIndex', index) + .set('currentInputValue', expression); if (index === 0) { return nextState.delete('nextConsoleEntry'); @@ -47,62 +47,67 @@ function updateConsoleForHistoryIndex(state, index) { return nextState; } -export default handleActions({ - [consoleValueProduced]: ( - state, - {payload: {compiledProjectKey, key, value}}, - ) => state.updateIn( - ['history', key], - input => input.set('value', value). - set('evaluatedByCompiledProjectKey', compiledProjectKey), - ), - - [consoleErrorProduced]: ( - state, - {payload: {compiledProjectKey, key, error}}, - ) => state.updateIn( - ['history', key], - input => input.set( - 'error', - Error.fromJS(error), - ).set('evaluatedByCompiledProjectKey', compiledProjectKey), - ), - - [evaluateConsoleEntry]: (state, {payload: expression, meta: {key}}) => - expression.trim() === '' ? - state : - state.setIn(['history', key], new ConsoleEntry({expression})). - delete('currentInputValue'). - delete('nextConsoleEntry'). - delete('historyEntryIndex'), - - [clearConsoleEntries]: constant(initialState), - - [consoleInputChanged]: (state, {payload: {value}}) => - state.set('currentInputValue', value), - - [consoleLogBatchProduced]: (state, {payload: {entries}}) => - state.update( - 'history', - history => history.withMutations((map) => { - entries.forEach(({value, compiledProjectKey, key}) => { - map.set(key, new ConsoleEntry({ - value, - evaluatedByCompiledProjectKey: compiledProjectKey, - })); - }); - }), - ), - - [previousConsoleHistory]: (state) => { - const historyIndex = state.historyEntryIndex + 1; - - return updateConsoleForHistoryIndex(state, historyIndex); - }, - - [nextConsoleHistory]: (state) => { - const historyIndex = state.historyEntryIndex - 1; - return updateConsoleForHistoryIndex(state, historyIndex); +export default handleActions( + { + [consoleValueProduced]: ( + state, + {payload: {compiledProjectKey, key, value}}, + ) => + state.updateIn(['history', key], input => + input + .set('value', value) + .set('evaluatedByCompiledProjectKey', compiledProjectKey), + ), + + [consoleErrorProduced]: ( + state, + {payload: {compiledProjectKey, key, error}}, + ) => + state.updateIn(['history', key], input => + input + .set('error', Error.fromJS(error)) + .set('evaluatedByCompiledProjectKey', compiledProjectKey), + ), + + [evaluateConsoleEntry]: (state, {payload: expression, meta: {key}}) => + expression.trim() === '' + ? state + : state + .setIn(['history', key], new ConsoleEntry({expression})) + .delete('currentInputValue') + .delete('nextConsoleEntry') + .delete('historyEntryIndex'), + + [clearConsoleEntries]: constant(initialState), + + [consoleInputChanged]: (state, {payload: {value}}) => + state.set('currentInputValue', value), + + [consoleLogBatchProduced]: (state, {payload: {entries}}) => + state.update('history', history => + history.withMutations(map => { + entries.forEach(({value, compiledProjectKey, key}) => { + map.set( + key, + new ConsoleEntry({ + value, + evaluatedByCompiledProjectKey: compiledProjectKey, + }), + ); + }); + }), + ), + + [previousConsoleHistory]: state => { + const historyIndex = state.historyEntryIndex + 1; + + return updateConsoleForHistoryIndex(state, historyIndex); + }, + + [nextConsoleHistory]: state => { + const historyIndex = state.historyEntryIndex - 1; + return updateConsoleForHistoryIndex(state, historyIndex); + }, }, -}, initialState); - + initialState, +); diff --git a/src/reducers/errors.js b/src/reducers/errors.js index a197fe3fc9..1702cc48ff 100644 --- a/src/reducers/errors.js +++ b/src/reducers/errors.js @@ -52,13 +52,14 @@ function errors(stateIn, action) { return state.set(action.payload.language, validatingLanguageErrors); case 'ADD_RUNTIME_ERROR': - return state.update( - action.payload.language, - list => list.update( - 'items', - items => items.push(Error.fromJS(action.payload.error)). - sortBy(error => error.get('row')), - ).set('state', 'runtime-error'), + return state.update(action.payload.language, list => + list + .update('items', items => + items + .push(Error.fromJS(action.payload.error)) + .sortBy(error => error.get('row')), + ) + .set('state', 'runtime-error'), ); case 'VALIDATED_SOURCE': @@ -71,15 +72,12 @@ function errors(stateIn, action) { return state.set(action.payload.language, passedLanguageErrors); case 'REFRESH_PREVIEW': - return state.update( - 'javascript', - (errorList) => { - if (errorList.state === 'runtime-error') { - return passedLanguageErrors; - } - return errorList; - }, - ); + return state.update('javascript', errorList => { + if (errorList.state === 'runtime-error') { + return passedLanguageErrors; + } + return errorList; + }); default: return state; diff --git a/src/reducers/googleClassroom.js b/src/reducers/googleClassroom.js index 6a36c05b1d..b212b414de 100644 --- a/src/reducers/googleClassroom.js +++ b/src/reducers/googleClassroom.js @@ -1,16 +1,9 @@ -import { - Course, - GoogleClassroom, - RemoteCollection, -} from '../records'; +import {Course, GoogleClassroom, RemoteCollection} from '../records'; const defaultState = new GoogleClassroom(); function addCourse(state, course) { - return state.setIn( - ['courses', 'items', course.id], - new Course(course), - ); + return state.setIn(['courses', 'items', course.id], new Course(course)); } export default function googleClassroom(stateIn, action) { @@ -24,16 +17,10 @@ export default function googleClassroom(stateIn, action) { return action.payload.courses.reduce(addCourse, state); case 'COURSES_FULLY_LOADED': - return state.setIn( - ['courses', 'isFullyLoaded'], - true, - ); + return state.setIn(['courses', 'isFullyLoaded'], true); case 'LOG_OUT': - return state.setIn( - ['courses'], - new RemoteCollection(), - ); + return state.setIn(['courses'], new RemoteCollection()); default: return state; diff --git a/src/reducers/index.js b/src/reducers/index.js index 4d7063c135..2994868960 100644 --- a/src/reducers/index.js +++ b/src/reducers/index.js @@ -27,7 +27,4 @@ const reduceRoot = combineReducers({ form: formReducer, }); -export default reduceReducers( - reduceRoot, - reduceRootForProjects, -); +export default reduceReducers(reduceRoot, reduceRootForProjects); diff --git a/src/reducers/projects.js b/src/reducers/projects.js index e0a222b0f3..6cd790dfad 100644 --- a/src/reducers/projects.js +++ b/src/reducers/projects.js @@ -17,24 +17,25 @@ const emptyMap = new Immutable.Map(); function addProject(state, project) { return state.set( project.projectKey, - Project.fromJS(project).update( - 'hiddenUIComponents', - components => components.add('console'), + Project.fromJS(project).update('hiddenUIComponents', components => + components.add('console'), ), ); } function removePristineExcept(state, keepProjectKey) { - return state.filter((project, projectKey) => ( - projectKey === keepProjectKey || !isPristineProject(project) - )); + return state.filter( + (project, projectKey) => + projectKey === keepProjectKey || !isPristineProject(project), + ); } function unhideComponent(state, projectKey, component, timestamp) { - return state.updateIn( - [projectKey, 'hiddenUIComponents'], - hiddenUIComponents => hiddenUIComponents.delete(component), - ).setIn([projectKey, 'updatedAt'], timestamp); + return state + .updateIn([projectKey, 'hiddenUIComponents'], hiddenUIComponents => + hiddenUIComponents.delete(component), + ) + .setIn([projectKey, 'updatedAt'], timestamp); } function contentForLanguage(files, language) { @@ -50,29 +51,28 @@ function importGist(state, projectKey, gistData) { const popcodeJsonFile = find(files, {filename: 'popcode.json'}); const popcodeJson = JSON.parse(get(popcodeJsonFile, 'content', '{}')); - return addProject( - state, - { - projectKey, - sources: { - html: get(find(files, {language: 'HTML'}), 'content', ''), - css: contentForLanguage(files, 'CSS'), - javascript: contentForLanguage(files, 'JavaScript'), - }, - enabledLibraries: popcodeJson.enabledLibraries || [], - hiddenUIComponents: popcodeJson.hiddenUIComponents || [], - instructions: contentForLanguage(files, 'Markdown'), - isArchived: false, + return addProject(state, { + projectKey, + sources: { + html: get(find(files, {language: 'HTML'}), 'content', ''), + css: contentForLanguage(files, 'CSS'), + javascript: contentForLanguage(files, 'JavaScript'), }, - ); + enabledLibraries: popcodeJson.enabledLibraries || [], + hiddenUIComponents: popcodeJson.hiddenUIComponents || [], + instructions: contentForLanguage(files, 'Markdown'), + isArchived: false, + }); } export function reduceRoot(stateIn, action) { - return stateIn.update('projects', (projects) => { + return stateIn.update('projects', projects => { switch (action.type) { case 'USER_LOGGED_OUT': { - const currentProjectKey = - stateIn.getIn(['currentProject', 'projectKey']); + const currentProjectKey = stateIn.getIn([ + 'currentProject', + 'projectKey', + ]); if (isNil(currentProjectKey)) { return new Immutable.Map(); @@ -95,7 +95,6 @@ export function reduceRoot(stateIn, action) { }); } -/* eslint-disable complexity */ export default function reduceProjects(stateIn, action) { let state; @@ -113,31 +112,28 @@ export default function reduceProjects(stateIn, action) { return action.payload.projects.reduce(addProject, state); case 'UPDATE_PROJECT_SOURCE': - return state.setIn( - [action.payload.projectKey, 'sources', action.payload.language], - action.payload.newValue, - ).setIn( - [action.payload.projectKey, 'updatedAt'], - action.meta.timestamp, - ); + return state + .setIn( + [action.payload.projectKey, 'sources', action.payload.language], + action.payload.newValue, + ) + .setIn([action.payload.projectKey, 'updatedAt'], action.meta.timestamp); case 'PROJECT_BEAUTIFIED': - return state.setIn( - [action.payload.projectKey, 'sources'], - new ProjectSources(action.payload.projectSources), - ).setIn( - [action.payload.projectKey, 'updatedAt'], - action.meta.timestamp, - ); + return state + .setIn( + [action.payload.projectKey, 'sources'], + new ProjectSources(action.payload.projectSources), + ) + .setIn([action.payload.projectKey, 'updatedAt'], action.meta.timestamp); case 'UPDATE_PROJECT_INSTRUCTIONS': - return state.setIn( - [action.payload.projectKey, 'instructions'], - action.payload.newValue, - ).setIn( - [action.payload.projectKey, 'updatedAt'], - action.meta.timestamp, - ); + return state + .setIn( + [action.payload.projectKey, 'instructions'], + action.payload.newValue, + ) + .setIn([action.payload.projectKey, 'updatedAt'], action.meta.timestamp); case 'PROJECT_CREATED': return removePristineExcept(state, action.payload.projectKey).set( @@ -154,11 +150,10 @@ export default function reduceProjects(stateIn, action) { case 'SNAPSHOT_IMPORTED': return addProject( state, - assign( - {}, - action.payload.project, - {projectKey: action.payload.projectKey, updatedAt: null}, - ), + assign({}, action.payload.project, { + projectKey: action.payload.projectKey, + updatedAt: null, + }), ); case 'GIST_IMPORTED': @@ -172,29 +167,27 @@ export default function reduceProjects(stateIn, action) { return addProject(state, action.payload); case 'TOGGLE_LIBRARY': - return state.updateIn( - [action.payload.projectKey, 'enabledLibraries'], - (enabledLibraries) => { - const {libraryKey} = action.payload; - if (enabledLibraries.has(libraryKey)) { - return enabledLibraries.delete(libraryKey); - } - return enabledLibraries.add(libraryKey); - }, - ).setIn( - [action.payload.projectKey, 'updatedAt'], - action.meta.timestamp, - ); + return state + .updateIn( + [action.payload.projectKey, 'enabledLibraries'], + enabledLibraries => { + const {libraryKey} = action.payload; + if (enabledLibraries.has(libraryKey)) { + return enabledLibraries.delete(libraryKey); + } + return enabledLibraries.add(libraryKey); + }, + ) + .setIn([action.payload.projectKey, 'updatedAt'], action.meta.timestamp); case 'HIDE_COMPONENT': - return state.updateIn( - [action.payload.projectKey, 'hiddenUIComponents'], - hiddenUIComponents => - hiddenUIComponents.add(action.payload.componentName), - ).setIn( - [action.payload.projectKey, 'updatedAt'], - action.meta.timestamp, - ); + return state + .updateIn( + [action.payload.projectKey, 'hiddenUIComponents'], + hiddenUIComponents => + hiddenUIComponents.add(action.payload.componentName), + ) + .setIn([action.payload.projectKey, 'updatedAt'], action.meta.timestamp); case 'UNHIDE_COMPONENT': return unhideComponent( @@ -205,19 +198,18 @@ export default function reduceProjects(stateIn, action) { ); case 'TOGGLE_COMPONENT': - return state.updateIn( - [action.payload.projectKey, 'hiddenUIComponents'], - (hiddenUIComponents) => { - const {componentName} = action.payload; - if (hiddenUIComponents.includes(componentName)) { - return hiddenUIComponents.remove(action.payload.componentName); - } - return hiddenUIComponents.add(action.payload.componentName); - }, - ).setIn( - [action.payload.projectKey, 'updatedAt'], - action.meta.timestamp, - ); + return state + .updateIn( + [action.payload.projectKey, 'hiddenUIComponents'], + hiddenUIComponents => { + const {componentName} = action.payload; + if (hiddenUIComponents.includes(componentName)) { + return hiddenUIComponents.remove(action.payload.componentName); + } + return hiddenUIComponents.add(action.payload.componentName); + }, + ) + .setIn([action.payload.projectKey, 'updatedAt'], action.meta.timestamp); case 'START_EDITING_INSTRUCTIONS': return unhideComponent( @@ -228,23 +220,24 @@ export default function reduceProjects(stateIn, action) { ); case 'PROJECT_EXPORTED': - if (action.payload.exportType === 'repo' && - action.payload.exportData.name) { - return state.setIn( - [action.payload.projectKey, 'externalLocations', 'githubRepoName'], - action.payload.exportData.name, - ).setIn( - [action.payload.projectKey, 'updatedAt'], - action.meta.timestamp, - ); + if ( + action.payload.exportType === 'repo' && + action.payload.exportData.name + ) { + return state + .setIn( + [action.payload.projectKey, 'externalLocations', 'githubRepoName'], + action.payload.exportData.name, + ) + .setIn( + [action.payload.projectKey, 'updatedAt'], + action.meta.timestamp, + ); } return state; case 'ARCHIVE_PROJECT': - return state.setIn( - [action.payload.projectKey, 'isArchived'], - true, - ); + return state.setIn([action.payload.projectKey, 'isArchived'], true); default: return state; diff --git a/src/reducers/resizableFlex.js b/src/reducers/resizableFlex.js index 6b78df9e20..b0f6632df2 100644 --- a/src/reducers/resizableFlex.js +++ b/src/reducers/resizableFlex.js @@ -4,14 +4,16 @@ import reduce from 'lodash-es/reduce'; const defaultState = new Map(); -export default handleActions({ - UPDATE_RESIZABLE_FLEX: (state, {payload: {name, updates}}) => state.update( - name, - new List(), - flexStateIn => reduce( - updates, - (flexState, {index, flexGrow}) => flexState.set(index, flexGrow), - flexStateIn, - ), - ), -}, defaultState); +export default handleActions( + { + UPDATE_RESIZABLE_FLEX: (state, {payload: {name, updates}}) => + state.update(name, new List(), flexStateIn => + reduce( + updates, + (flexState, {index, flexGrow}) => flexState.set(index, flexGrow), + flexStateIn, + ), + ), + }, + defaultState, +); diff --git a/src/reducers/ui.js b/src/reducers/ui.js index eeef1501cb..b27ec47041 100644 --- a/src/reducers/ui.js +++ b/src/reducers/ui.js @@ -12,20 +12,17 @@ function addNotification(state, type, severity, metadata = {}) { } function dismissNotification(state, type) { - return state.update( - 'notifications', - notifications => notifications.delete(type), + return state.update('notifications', notifications => + notifications.delete(type), ); } function closeTopBarMenu(state, menuToClose) { - return state.update( - 'openTopBarMenu', - menu => menu === menuToClose ? null : menu, + return state.update('openTopBarMenu', menu => + menu === menuToClose ? null : menu, ); } -/* eslint-disable complexity */ export default function ui(stateIn, action) { let state = stateIn; if (state === undefined) { @@ -34,20 +31,20 @@ export default function ui(stateIn, action) { switch (action.type) { case 'CHANGE_CURRENT_PROJECT': - return state. - set('isEditingInstructions', false). - update( - 'openTopBarMenu', - menu => menu === 'projectPicker' ? null : menu, - ).set('archivedViewOpen', false); + return state + .set('isEditingInstructions', false) + .update('openTopBarMenu', menu => + menu === 'projectPicker' ? null : menu, + ) + .set('archivedViewOpen', false); case 'PROJECT_CREATED': return state.set('isEditingInstructions', false); case 'UPDATE_PROJECT_SOURCE': - return state. - set('isTyping', true). - deleteIn(['notifications', 'snapshot-created']); + return state + .set('isTyping', true) + .deleteIn(['notifications', 'snapshot-created']); case 'USER_DONE_TYPING': return state.set('isTyping', false); @@ -82,20 +79,14 @@ export default function ui(stateIn, action) { return state.set('isDraggingColumnDivider', false); case 'GIST_NOT_FOUND': - return addNotification( - state, - 'gist-import-not-found', - 'error', - {gistId: action.payload.gistId}, - ); + return addNotification(state, 'gist-import-not-found', 'error', { + gistId: action.payload.gistId, + }); case 'GIST_IMPORT_ERROR': - return addNotification( - state, - 'gist-import-error', - 'error', - {gistId: action.payload.gistId}, - ); + return addNotification(state, 'gist-import-error', 'error', { + gistId: action.payload.gistId, + }); case 'NOTIFICATION_TRIGGERED': return addNotification( @@ -120,19 +111,12 @@ export default function ui(stateIn, action) { return closeTopBarMenu(state, 'currentUser'); case 'IDENTITY_UNLINKED': - return addNotification( - state, - 'identity-unlinked', - 'notice', - ); + return addNotification(state, 'identity-unlinked', 'notice'); case 'SNAPSHOT_CREATED': - return addNotification( - state, - 'snapshot-created', - 'notice', - {snapshotKey: action.payload}, - ); + return addNotification(state, 'snapshot-created', 'notice', { + snapshotKey: action.payload, + }); case 'APPLICATION_LOADED': if (action.payload.isExperimental) { @@ -156,15 +140,13 @@ export default function ui(stateIn, action) { ); case 'TOGGLE_TOP_BAR_MENU': - return state.update( - 'openTopBarMenu', - menu => menu === action.payload ? null : action.payload, + return state.update('openTopBarMenu', menu => + menu === action.payload ? null : action.payload, ); case 'CLOSE_TOP_BAR_MENU': - return state.update( - 'openTopBarMenu', - menu => menu === action.payload ? null : menu, + return state.update('openTopBarMenu', menu => + menu === action.payload ? null : menu, ); case 'PROJECT_EXPORT_NOT_DISPLAYED': @@ -177,11 +159,7 @@ export default function ui(stateIn, action) { case 'PROJECT_EXPORT_ERROR': if (action.payload.name === 'EmptyGistError') { - return addNotification( - state, - 'empty-gist', - 'error', - ); + return addNotification(state, 'empty-gist', 'error'); } return addNotification( state, @@ -191,11 +169,7 @@ export default function ui(stateIn, action) { ); case 'PROJECT_COMPILATION_FAILED': - return addNotification( - state, - 'project-compilation-failed', - 'error', - ); + return addNotification(state, 'project-compilation-failed', 'error'); case 'PROJECT_COMPILED': return dismissNotification(state, 'project-compilation-failed'); @@ -219,27 +193,18 @@ export default function ui(stateIn, action) { ); case 'IDENTITY_LINKED': - return addNotification( - state, - 'identity-linked', - 'notice', - {provider: action.payload.credential.providerId}, - ); + return addNotification(state, 'identity-linked', 'notice', { + provider: action.payload.credential.providerId, + }); case 'LINK_IDENTITY_FAILED': return addNotification(state, 'link-identity-failed', 'error'); case 'OPEN_ASSIGNMENT_CREATOR': - return state.setIn( - ['isAssignmentCreatorOpen'], - true, - ); + return state.setIn(['isAssignmentCreatorOpen'], true); case 'CLOSE_ASSIGNMENT_CREATOR': - return state.setIn( - ['isAssignmentCreatorOpen'], - false, - ); + return state.setIn(['isAssignmentCreatorOpen'], false); case 'ASSIGNMENT_CREATED': return addNotification( @@ -247,20 +212,13 @@ export default function ui(stateIn, action) { 'project-export-complete', 'notice', action.payload.assignment, - ).setIn( - ['isAssignmentCreatorOpen'], - false, - ); + ).setIn(['isAssignmentCreatorOpen'], false); case 'GAPI_CLIENT_UNAVAILABLE': return addNotification(state, 'gapi-client-unavailable', 'error'); case 'ASSIGNMENT_NOT_CREATED': - return addNotification( - state, - 'assignment-not-created', - 'error', - ).setIn( + return addNotification(state, 'assignment-not-created', 'error').setIn( ['isAssignmentCreatorOpen'], false, ); diff --git a/src/reducers/user.js b/src/reducers/user.js index 8a8afdb47f..691376ab77 100644 --- a/src/reducers/user.js +++ b/src/reducers/user.js @@ -21,10 +21,9 @@ function getToken(credential) { } function addIdentityProvider(state, userData, credential) { - const providerData = find( - userData.providerData, - {providerId: credential.providerId}, - ); + const providerData = find(userData.providerData, { + providerId: credential.providerId, + }); if (isUndefined(providerData)) { return state; } diff --git a/src/sagas/assignments.js b/src/sagas/assignments.js index cbff070cdf..3ce8a23b48 100644 --- a/src/sagas/assignments.js +++ b/src/sagas/assignments.js @@ -4,21 +4,10 @@ import { getCourses, createClassroomAssignment, } from '../clients/googleClassroom'; -import { - createProjectSnapshot, -} from '../clients/firebase'; -import { - assignmentCreated, - assignmentNotCreated, -} from '../actions/assignments'; -import { - coursesLoaded, - coursesFullyLoaded, -} from '../actions/ui'; -import { - getCourse, - getCurrentProject, -} from '../selectors'; +import {createProjectSnapshot} from '../clients/firebase'; +import {assignmentCreated, assignmentNotCreated} from '../actions/assignments'; +import {coursesLoaded, coursesFullyLoaded} from '../actions/ui'; +import {getCourse, getCurrentProject} from '../selectors'; import {generateTextPreview} from '../util/compileProject'; import {createSnapshotUrl} from '../util/exportUrls'; @@ -32,9 +21,9 @@ export function* openAssignmentCreator() { yield put(coursesFullyLoaded()); } -export function* createAssignment( - {payload: {selectedCourseId, dueDate, assignmentState}}, -) { +export function* createAssignment({ + payload: {selectedCourseId, dueDate, assignmentState}, +}) { const project = yield select(getCurrentProject); const snapshotKey = yield call(createProjectSnapshot, project); const [url, title] = yield all([ @@ -51,16 +40,20 @@ export function* createAssignment( try { const assignment = yield call(createClassroomAssignment, assignmentData); if (assignment.alternateLink) { - yield put(assignmentCreated({ - url: assignment.alternateLink, - exportType: 'assignment', - })); + yield put( + assignmentCreated({ + url: assignment.alternateLink, + exportType: 'assignment', + }), + ); } else { const course = yield select(getCourse, selectedCourseId); - yield put(assignmentCreated({ - url: course.alternateLink, - exportType: 'assignment-draft', - })); + yield put( + assignmentCreated({ + url: course.alternateLink, + exportType: 'assignment-draft', + }), + ); } } catch (e) { yield put(assignmentNotCreated()); diff --git a/src/sagas/clients.js b/src/sagas/clients.js index 7da9533a1c..e6daa15f30 100644 --- a/src/sagas/clients.js +++ b/src/sagas/clients.js @@ -3,9 +3,7 @@ import { createGistFromProject, createOrUpdateRepoFromProject, } from '../clients/github'; -import { - createShareToClassroomUrl, -} from '../clients/googleClassroom'; +import {createShareToClassroomUrl} from '../clients/googleClassroom'; import {createProjectSnapshot} from '../clients/firebase'; import { snapshotCreated, @@ -20,7 +18,6 @@ import {generateTextPreview} from '../util/compileProject'; import {bugsnagClient} from '../util/bugsnag'; import {loadAndConfigureGapi} from '../services/gapi'; - export function* createSnapshot() { const project = yield select(getCurrentProject); try { @@ -42,13 +39,19 @@ export function* exportProject({payload: {exportType}}) { if (exportType === 'gist') { const {accessToken} = user.account.identityProviders.get('github.com'); - ({html_url: url} = - yield call(createGistFromProject, project, accessToken)); + ({html_url: url} = yield call( + createGistFromProject, + project, + accessToken, + )); } else if (exportType === 'repo') { const {accessToken} = user.account.identityProviders.get('github.com'); - ({url, name} = - yield call(createOrUpdateRepoFromProject, project, accessToken)); + ({url, name} = yield call( + createOrUpdateRepoFromProject, + project, + accessToken, + )); if (name) { exportData = {name}; } @@ -57,12 +60,7 @@ export function* exportProject({payload: {exportType}}) { const projectTitle = yield call(generateTextPreview, project); url = yield call(createShareToClassroomUrl, snapshotKey, projectTitle); } - yield put(projectExported( - url, - exportType, - project.projectKey, - exportData, - )); + yield put(projectExported(url, exportType, project.projectKey, exportData)); } catch (e) { yield put(projectExportError(exportType)); } diff --git a/src/sagas/compiledProjects.js b/src/sagas/compiledProjects.js index f89d6667b1..da3b215197 100644 --- a/src/sagas/compiledProjects.js +++ b/src/sagas/compiledProjects.js @@ -1,11 +1,4 @@ -import { - all, - call, - put, - select, - throttle, - takeEvery, -} from 'redux-saga/effects'; +import {all, call, put, select, throttle, takeEvery} from 'redux-saga/effects'; import every from 'lodash-es/every'; @@ -20,11 +13,9 @@ export function* validatedSource() { const currentProject = yield select(getCurrentProject); const timestamp = Date.now(); try { - const preview = yield call( - compileProject, - currentProject, - {isInlinePreview: true}, - ); + const preview = yield call(compileProject, currentProject, { + isInlinePreview: true, + }); yield put(projectCompiled(preview, timestamp)); } catch (e) { yield call([bugsnagClient, 'notify'], e); diff --git a/src/sagas/errors.js b/src/sagas/errors.js index 3a75b695bb..806b71e94f 100644 --- a/src/sagas/errors.js +++ b/src/sagas/errors.js @@ -14,10 +14,10 @@ import {validatedSource} from '../actions/errors'; import retryingFailedImports from '../util/retryingFailedImports'; export async function importValidations() { - return retryingFailedImports( - () => import( + return retryingFailedImports(() => + import( /* webpackChunkName: "mainAsync" */ - '../validations' // eslint-disable-line comma-dangle + '../validations' ), ); } @@ -29,11 +29,9 @@ export function* toggleLibrary(tasks) { export function* updateProjectSource(tasks, {payload: {language, newValue}}) { const state = yield select(); const analyzer = new Analyzer(getCurrentProject(state)); - yield call( - validateSource, - tasks, - {payload: {language, source: newValue, projectAttributes: analyzer}}, - ); + yield call(validateSource, tasks, { + payload: {language, source: newValue, projectAttributes: analyzer}, + }); } export function* validateCurrentProject(tasks) { @@ -43,11 +41,9 @@ export function* validateCurrentProject(tasks) { for (const language of Reflect.ownKeys(currentProject.sources)) { const source = currentProject.sources[language]; - yield fork( - validateSource, - tasks, - {payload: {language, source, projectAttributes: analyzer}}, - ); + yield fork(validateSource, tasks, { + payload: {language, source, projectAttributes: analyzer}, + }); } } diff --git a/src/sagas/manageUserState.js b/src/sagas/manageUserState.js index 4b6b2eec3e..396370ac4e 100644 --- a/src/sagas/manageUserState.js +++ b/src/sagas/manageUserState.js @@ -59,10 +59,9 @@ export function* handleAuthChange(user, {newCredential} = {}) { if (isNil(newCredential)) { credentials = storedCredentials; } else { - credentials = reject( - storedCredentials, - {providerId: newCredential.providerId}, - ); + credentials = reject(storedCredentials, { + providerId: newCredential.providerId, + }); credentials.push(newCredential); } @@ -90,9 +89,7 @@ export function* handleAuthError(e) { case 'auth/web-storage-unsupported': case 'auth/operation-not-supported-in-this-environment': - yield put( - notificationTriggered('auth-third-party-cookies-disabled'), - ); + yield put(notificationTriggered('auth-third-party-cookies-disabled')); break; case 'access_denied': @@ -127,11 +124,10 @@ function* reportUserCredentialMismatch(user, credentials) { `User ${user.uid} has credentials for ` + `${missingUserProviders.join(',')} + but no linked account`, ); - yield call( - [bugsnagClient, 'notify'], - e, - {metaData: {user, credentials}, severity: 'warning'}, - ); + yield call([bugsnagClient, 'notify'], e, { + metaData: {user, credentials}, + severity: 'warning', + }); } if (!isEmpty(missingCredentialProviders)) { @@ -139,11 +135,10 @@ function* reportUserCredentialMismatch(user, credentials) { `User ${user.uid} has linked accounts for ` + `${missingCredentialProviders.join(',')} + but no credentials`, ); - yield call( - [bugsnagClient, 'notify'], - e, - {metaData: {user, credentials}, severity: 'warning'}, - ); + yield call([bugsnagClient, 'notify'], e, { + metaData: {user, credentials}, + severity: 'warning', + }); } } diff --git a/src/sagas/projects.js b/src/sagas/projects.js index 0bd92c2649..43b616e9cf 100644 --- a/src/sagas/projects.js +++ b/src/sagas/projects.js @@ -36,11 +36,7 @@ import { saveProject, } from '../clients/firebase'; import beautifySource from '../util/beautifySource'; -import { - getCurrentProject, - getProject, - getCurrentUserId, -} from '../selectors'; +import {getCurrentProject, getProject, getCurrentUserId} from '../selectors'; export function* applicationLoaded(action) { if (isString(action.payload.gistId)) { @@ -48,9 +44,7 @@ export function* applicationLoaded(action) { } else if (isString(action.payload.snapshotKey)) { yield call(importSnapshot, action); } else if (action.payload.rehydratedProject) { - yield put( - projectRestoredFromLastSession(action.payload.rehydratedProject), - ); + yield put(projectRestoredFromLastSession(action.payload.rehydratedProject)); } else { yield call(createProject); } @@ -80,8 +74,7 @@ export function* importSnapshot({payload: {snapshotKey}}) { export function* importGist({payload: {gistId}}) { try { - const gistData = - yield call(loadGistFromId, gistId); + const gistData = yield call(loadGistFromId, gistId); yield put(gistImported(generateProjectKey(), gistData)); } catch (error) { if (get(error, 'response.status') === 404) { @@ -101,13 +94,10 @@ export function* loadAndBeautifyProjectSource() { const sourcesMap = yield all( reduce( currentProject.sources, - (calls, source, language) => Object.assign(calls, { - [language]: call( - beautifySource, - source, - language, - ), - }), + (calls, source, language) => + Object.assign(calls, { + [language]: call(beautifySource, source, language), + }), {}, ), ); @@ -169,10 +159,11 @@ export default function* projects() { takeEvery('CREATE_PROJECT', createProject), takeEvery('CHANGE_CURRENT_PROJECT', changeCurrentProject), takeEvery('PROJECT_EXPORTED', projectExported), - throttle(500, [ - 'UPDATE_PROJECT_SOURCE', - 'UPDATE_PROJECT_INSTRUCTIONS', - ], updateProjectSource), + throttle( + 500, + ['UPDATE_PROJECT_SOURCE', 'UPDATE_PROJECT_INSTRUCTIONS'], + updateProjectSource, + ), takeEvery('USER_AUTHENTICATED', userAuthenticated), takeEvery('TOGGLE_LIBRARY', toggleLibrary), takeLatest('BEAUTIFY_PROJECT_SOURCE', loadAndBeautifyProjectSource), diff --git a/src/sagas/ui.js b/src/sagas/ui.js index 45e7ea2f0f..be63217545 100644 --- a/src/sagas/ui.js +++ b/src/sagas/ui.js @@ -38,10 +38,11 @@ function* projectExport( notDisplayedAction, displayedAction, ) { - const exportWindow = - yield call(openWindowWithContent, spinnerPageHtml); - const {type, payload: {url, exportType}} = - yield take([successAction, failureAction]); + const exportWindow = yield call(openWindowWithContent, spinnerPageHtml); + const { + type, + payload: {url, exportType}, + } = yield take([successAction, failureAction]); if (type === successAction) { if (exportWindow.closed) { yield put(notDisplayedAction(url, exportType)); diff --git a/src/sagas/user.js b/src/sagas/user.js index 8a35454391..a03ceabdd5 100644 --- a/src/sagas/user.js +++ b/src/sagas/user.js @@ -15,10 +15,7 @@ import { accountMigrationError, } from '../actions/user'; import {getCurrentAccountMigration} from '../selectors'; -import { - migrateAccount, - signOut, -} from '../clients/firebase'; +import {migrateAccount, signOut} from '../clients/firebase'; export function* startAccountMigration() { const {shouldContinue} = yield race({ @@ -33,14 +30,14 @@ export function* startAccountMigration() { yield put(accountMigrationUndoPeriodExpired()); const {firebaseCredential} = yield select(getCurrentAccountMigration); try { - const {user: userData, migratedProjects} = - yield call(migrateAccount, firebaseCredential); - - yield put(accountMigrationComplete( - userData, + const {user: userData, migratedProjects} = yield call( + migrateAccount, firebaseCredential, - migratedProjects, - )); + ); + + yield put( + accountMigrationComplete(userData, firebaseCredential, migratedProjects), + ); } catch (e) { yield call([bugsnagClient, 'notify'], e); yield put(accountMigrationError(e)); diff --git a/src/selectors/getAllProjectKeys.js b/src/selectors/getAllProjectKeys.js index bbe99918cf..a24b41d4a2 100644 --- a/src/selectors/getAllProjectKeys.js +++ b/src/selectors/getAllProjectKeys.js @@ -3,24 +3,27 @@ import isNull from 'lodash-es/isNull'; export default createSelector( state => state.get('projects'), - projects => projects. - sort(( - {updatedAt: firstProjectUpdatedAt}, - {updatedAt: secondProjectUpdatedAt}, - ) => { - const isFirstProjectPristine = isNull(firstProjectUpdatedAt); - const isSecondProjectPristine = isNull(secondProjectUpdatedAt); - if (isFirstProjectPristine) { - if (isSecondProjectPristine) { - return 0; - } - return -1; - } - if (isSecondProjectPristine) { - return 1; - } - return secondProjectUpdatedAt - firstProjectUpdatedAt; - }). - keySeq(). - toJS(), + projects => + projects + .sort( + ( + {updatedAt: firstProjectUpdatedAt}, + {updatedAt: secondProjectUpdatedAt}, + ) => { + const isFirstProjectPristine = isNull(firstProjectUpdatedAt); + const isSecondProjectPristine = isNull(secondProjectUpdatedAt); + if (isFirstProjectPristine) { + if (isSecondProjectPristine) { + return 0; + } + return -1; + } + if (isSecondProjectPristine) { + return 1; + } + return secondProjectUpdatedAt - firstProjectUpdatedAt; + }, + ) + .keySeq() + .toJS(), ); diff --git a/src/selectors/getAllProjects.js b/src/selectors/getAllProjects.js index 4901cea105..364bd3cbec 100644 --- a/src/selectors/getAllProjects.js +++ b/src/selectors/getAllProjects.js @@ -4,8 +4,5 @@ import values from 'lodash-es/values'; export default createSelector( state => state.get('projects'), - projects => sortBy( - values(projects.toJS()), - project => -project.updatedAt, - ), + projects => sortBy(values(projects.toJS()), project => -project.updatedAt), ); diff --git a/src/selectors/getCourse.js b/src/selectors/getCourse.js index 4126cb0bae..94baa5a4aa 100644 --- a/src/selectors/getCourse.js +++ b/src/selectors/getCourse.js @@ -1,9 +1,4 @@ export default function getCourse(state, courseId) { - const course = state.getIn([ - 'googleClassroom', - 'courses', - 'items', - courseId, - ]); + const course = state.getIn(['googleClassroom', 'courses', 'items', courseId]); return course; } diff --git a/src/selectors/getCourses.js b/src/selectors/getCourses.js index cbb377857b..3c9d9cfa99 100644 --- a/src/selectors/getCourses.js +++ b/src/selectors/getCourses.js @@ -1,7 +1,3 @@ export default function getCourses(state) { - return state.getIn([ - 'googleClassroom', - 'courses', - 'items', - ]); + return state.getIn(['googleClassroom', 'courses', 'items']); } diff --git a/src/selectors/getCurrentCompiledProjectKey.js b/src/selectors/getCurrentCompiledProjectKey.js index 76300307e5..45aa5822e5 100644 --- a/src/selectors/getCurrentCompiledProjectKey.js +++ b/src/selectors/getCurrentCompiledProjectKey.js @@ -1,8 +1,5 @@ import get from 'lodash-es/get'; export default function getCurrentCompiledProjectKey(state) { - return get( - state.get('compiledProjects').last(), - 'compiledProjectKey', - ); + return get(state.get('compiledProjects').last(), 'compiledProjectKey'); } diff --git a/src/selectors/getCurrentProjectExportedRepoName.js b/src/selectors/getCurrentProjectExportedRepoName.js index 44d1e36048..bfe4c5ed08 100644 --- a/src/selectors/getCurrentProjectExportedRepoName.js +++ b/src/selectors/getCurrentProjectExportedRepoName.js @@ -6,9 +6,7 @@ import getCurrentProject from './getCurrentProject'; export default createSelector( [getCurrentProject], currentProject => - currentProject ? get( - currentProject, - ['externalLocations', 'githubRepoName'], - null, - ) : null, + currentProject + ? get(currentProject, ['externalLocations', 'githubRepoName'], null) + : null, ); diff --git a/src/selectors/getCurrentProjectPreviewTitle.js b/src/selectors/getCurrentProjectPreviewTitle.js index a250ceb042..d5d8f0e4ea 100644 --- a/src/selectors/getCurrentProjectPreviewTitle.js +++ b/src/selectors/getCurrentProjectPreviewTitle.js @@ -5,7 +5,7 @@ import getCompiledProjects from './getCompiledProjects'; export default createSelector( [getCompiledProjects], - (compiledProjects) => { + compiledProjects => { const mostRecentCompiledProject = compiledProjects.last(); const title = get(mostRecentCompiledProject, 'title', ''); return title; diff --git a/src/selectors/getCurrentValidationState.js b/src/selectors/getCurrentValidationState.js index d566ddf624..a4616b90bd 100644 --- a/src/selectors/getCurrentValidationState.js +++ b/src/selectors/getCurrentValidationState.js @@ -2,7 +2,7 @@ import {createSelector} from 'reselect'; export default createSelector( state => state.get('errors'), - (errors) => { + errors => { const errorStates = [ errors.html.state, errors.css.state, diff --git a/src/selectors/getHiddenAndVisibleLanguages.js b/src/selectors/getHiddenAndVisibleLanguages.js index f95ec02af9..19f14ae612 100644 --- a/src/selectors/getHiddenAndVisibleLanguages.js +++ b/src/selectors/getHiddenAndVisibleLanguages.js @@ -9,18 +9,11 @@ import getHiddenUIComponents from './getHiddenUIComponents'; export default createSelector( [getHiddenUIComponents], - (hiddenUIComponents) => { + hiddenUIComponents => { const [hiddenLanguages, visibleLanguages] = partition( - map( - LANGUAGES, - (language, index) => ({language, index}), - ), - ({language}) => includes( - hiddenUIComponents, - `editor.${language}`, - ), + map(LANGUAGES, (language, index) => ({language, index})), + ({language}) => includes(hiddenUIComponents, `editor.${language}`), ); return {hiddenLanguages, visibleLanguages}; }, ); - diff --git a/src/selectors/getParsedDate.js b/src/selectors/getParsedDate.js index e4af1bd9d1..74d76bd2a9 100644 --- a/src/selectors/getParsedDate.js +++ b/src/selectors/getParsedDate.js @@ -1,10 +1,5 @@ export default function getParsedDate(state) { - const date = state.getIn([ - 'form', - 'assignmentCreator', - 'values', - 'date', - ]); + const date = state.getIn(['form', 'assignmentCreator', 'values', 'date']); if (date) { return date.parsedDate; } diff --git a/src/selectors/index.js b/src/selectors/index.js index f9304972b7..12dd973547 100644 --- a/src/selectors/index.js +++ b/src/selectors/index.js @@ -9,8 +9,7 @@ import getCurrentCompiledProjectKey from './getCurrentCompiledProjectKey'; import getCurrentConsoleInputValue from './getCurrentConsoleInputValue'; import getCurrentProject from './getCurrentProject'; import getCurrentProjectInstructions from './getCurrentProjectInstructions'; -import getCurrentProjectExportedRepoName - from './getCurrentProjectExportedRepoName'; +import getCurrentProjectExportedRepoName from './getCurrentProjectExportedRepoName'; import getCurrentProjectPreview from './getCurrentProjectPreview'; import getCurrentProjectPreviewTitle from './getCurrentProjectPreviewTitle'; import getCurrentProjectKey from './getCurrentProjectKey'; @@ -31,8 +30,7 @@ import isAssignmentExportInProgress from './isAssignmentExportInProgress'; import isClassroomExportInProgress from './isClassroomExportInProgress'; import isArchivedViewOpen from './isArchivedViewOpen'; import isCurrentlyValidating from './isCurrentlyValidating'; -import isCurrentProjectSyntacticallyValid - from './isCurrentProjectSyntacticallyValid'; +import isCurrentProjectSyntacticallyValid from './isCurrentProjectSyntacticallyValid'; import isDraggingColumnDivider from './isDraggingColumnDivider'; import isEditingInstructions from './isEditingInstructions'; import isExperimental from './isExperimental'; @@ -49,8 +47,7 @@ import isUserAuthenticatedWithGithub from './isUserAuthenticatedWithGithub'; import isUserAuthenticatedWithGoogle from './isUserAuthenticatedWithGoogle'; import makeGetProjectPreview from './makeGetProjectPreview'; import makeGetResizableFlexGrow from './makeGetResizableFlexGrow'; -import makeIsRemoteCollectionFullyLoaded - from './makeIsRemoteCollectionFullyLoaded'; +import makeIsRemoteCollectionFullyLoaded from './makeIsRemoteCollectionFullyLoaded'; export { getAllProjectKeys, diff --git a/src/selectors/isAssignmentCreatorOpen.js b/src/selectors/isAssignmentCreatorOpen.js index 834814d460..563293cbb9 100644 --- a/src/selectors/isAssignmentCreatorOpen.js +++ b/src/selectors/isAssignmentCreatorOpen.js @@ -1,5 +1,3 @@ export default function isAssignmentCreatorOpen(state) { - return state.getIn( - ['ui', 'isAssignmentCreatorOpen'], - ); + return state.getIn(['ui', 'isAssignmentCreatorOpen']); } diff --git a/src/selectors/isAssignmentExportInProgress.js b/src/selectors/isAssignmentExportInProgress.js index 6a73b9305a..da02a26f25 100644 --- a/src/selectors/isAssignmentExportInProgress.js +++ b/src/selectors/isAssignmentExportInProgress.js @@ -1,6 +1,3 @@ export default function isAssignmentExportInProgress(state) { - return state.getIn([ - 'clients', - 'exportingAssignment', - ]); + return state.getIn(['clients', 'exportingAssignment']); } diff --git a/src/selectors/isCurrentProjectSyntacticallyValid.js b/src/selectors/isCurrentProjectSyntacticallyValid.js index 13ba3d84ca..f4f6101e68 100644 --- a/src/selectors/isCurrentProjectSyntacticallyValid.js +++ b/src/selectors/isCurrentProjectSyntacticallyValid.js @@ -4,7 +4,6 @@ const syntacticallyValidStates = new Set(['passed', 'runtime-error']); export default createSelector( state => state.get('errors'), - errors => !errors.find( - error => !syntacticallyValidStates.has(error.get('state')), - ), + errors => + !errors.find(error => !syntacticallyValidStates.has(error.get('state'))), ); diff --git a/src/selectors/isProjectExportInProgress.js b/src/selectors/isProjectExportInProgress.js index dec958ede6..9b89dc5ffb 100644 --- a/src/selectors/isProjectExportInProgress.js +++ b/src/selectors/isProjectExportInProgress.js @@ -1,5 +1,6 @@ export default function isProjectExportInProgress(state, exportKey) { - return state.getIn( - ['clients', 'projectExports', exportKey, 'status'], - ) === 'waiting'; + return ( + state.getIn(['clients', 'projectExports', exportKey, 'status']) === + 'waiting' + ); } diff --git a/src/selectors/isUserAuthenticatedWithGithub.js b/src/selectors/isUserAuthenticatedWithGithub.js index dd89824a9d..210c5e354c 100644 --- a/src/selectors/isUserAuthenticatedWithGithub.js +++ b/src/selectors/isUserAuthenticatedWithGithub.js @@ -1,5 +1,4 @@ import makeIsUserAuthenticatedWith from './makeIsUserAuthenticatedWith'; -const isUserAuthenticatedWithGithub = - makeIsUserAuthenticatedWith('github.com'); +const isUserAuthenticatedWithGithub = makeIsUserAuthenticatedWith('github.com'); export default isUserAuthenticatedWithGithub; diff --git a/src/selectors/isUserAuthenticatedWithGoogle.js b/src/selectors/isUserAuthenticatedWithGoogle.js index 16819b24b6..7493aceded 100644 --- a/src/selectors/isUserAuthenticatedWithGoogle.js +++ b/src/selectors/isUserAuthenticatedWithGoogle.js @@ -1,5 +1,4 @@ import makeIsUserAuthenticatedWith from './makeIsUserAuthenticatedWith'; -const isUserAuthenticatedWithGoogle = - makeIsUserAuthenticatedWith('google.com'); +const isUserAuthenticatedWithGoogle = makeIsUserAuthenticatedWith('google.com'); export default isUserAuthenticatedWithGoogle; diff --git a/src/selectors/makeIsUserAuthenticatedWith.js b/src/selectors/makeIsUserAuthenticatedWith.js index 9397709abd..7bdae7298e 100644 --- a/src/selectors/makeIsUserAuthenticatedWith.js +++ b/src/selectors/makeIsUserAuthenticatedWith.js @@ -2,13 +2,17 @@ import isUserAuthenticated from './isUserAuthenticated'; export default function makeIsUserAuthenticatedWith(provider) { return function isUserAuthenticatedWithProvider(state) { - return isUserAuthenticated(state) && - Boolean(state.getIn([ - 'user', - 'account', - 'identityProviders', - provider, - 'accessToken', - ])); + return ( + isUserAuthenticated(state) && + Boolean( + state.getIn([ + 'user', + 'account', + 'identityProviders', + provider, + 'accessToken', + ]), + ) + ); }; } diff --git a/src/services/gapi.js b/src/services/gapi.js index 6a4877b5e6..0863b93eb2 100644 --- a/src/services/gapi.js +++ b/src/services/gapi.js @@ -11,38 +11,42 @@ export const SCOPES = [ 'https://www.googleapis.com/auth/classroom.coursework.me', ]; -const DISCOVERY_DOCS = ['https://classroom.googleapis.com/$discovery/rest?version=v1']; +const DISCOVERY_DOCS = [ + 'https://classroom.googleapis.com/$discovery/rest?version=v1', +]; class LoadError extends ExtendableError {} let isGapiLoadedAndConfigured = false; -const loadGapi = once(() => promiseRetry( - async(retry) => { - try { - return await new Promise((resolve, reject) => { - loadjs('https://apis.google.com/js/client.js', { - success() { - resolve(window.gapi); - }, - error(failedPaths) { - reject(new LoadError(`Failed to load ${failedPaths.join(', ')}`)); - }, +const loadGapi = once(() => + promiseRetry( + async retry => { + try { + return await new Promise((resolve, reject) => { + loadjs('https://apis.google.com/js/client.js', { + success() { + resolve(window.gapi); + }, + error(failedPaths) { + reject(new LoadError(`Failed to load ${failedPaths.join(', ')}`)); + }, + }); }); - }); - } catch (e) { - return retry(e); - } - }, - { - retries: 16, - factor: 2, - minTimeout: 200, - maxTimeout: 4000, - }, -)); + } catch (e) { + return retry(e); + } + }, + { + retries: 16, + factor: 2, + minTimeout: 200, + maxTimeout: 4000, + }, + ), +); -export const loadAndConfigureGapi = once(async() => { +export const loadAndConfigureGapi = once(async () => { const gapi = await loadGapi(); await new Promise((resolve, reject) => { gapi.load('client:auth2', { diff --git a/src/services/inlineStylePrefixer/prefixData.gen.js b/src/services/inlineStylePrefixer/prefixData.gen.js index f117a16fe7..0060d7f0be 100644 --- a/src/services/inlineStylePrefixer/prefixData.gen.js +++ b/src/services/inlineStylePrefixer/prefixData.gen.js @@ -1,5 +1,5 @@ const { - 'default': generateData, + default: generateData, generateFile, } = require('inline-style-prefixer/lib/generator'); @@ -10,13 +10,11 @@ module.exports = () => { for (const browser in browserList) { if (browser !== 'chromium') { - browserListForInlineStylePrefixer[browser] = - Number(browserList[browser]); + browserListForInlineStylePrefixer[browser] = Number(browserList[browser]); } } - const {prefixMap, plugins} = - generateData(browserListForInlineStylePrefixer); + const {prefixMap, plugins} = generateData(browserListForInlineStylePrefixer); return {code: generateFile(prefixMap, plugins, false)}; }; diff --git a/src/static/privacy.html b/src/static/privacy.html index 7c5299ae5f..8025ae0a1f 100644 --- a/src/static/privacy.html +++ b/src/static/privacy.html @@ -4,27 +4,61 @@

    Privacy Notice

    -

    This privacy notice discloses the privacy practices for Popcode. This privacy notice applies solely to information collected by this website. It will notify you of the following:

    +

    + This privacy notice discloses the privacy practices for + Popcode. This privacy notice applies + solely to information collected by this website. It will notify you of the + following: +

      -
    • What personally identifiable information is collected from you through the website, how it is used and with whom it may be shared.
    • +
    • + What personally identifiable information is collected from you through + the website, how it is used and with whom it may be shared. +
    • What choices are available to you regarding the use of your data.
    • -
    • The security procedures in place to protect the misuse of your information.
    • +
    • + The security procedures in place to protect the misuse of your + information. +
    • How you can correct any inaccuracies in the information.

    Information Collection, Use, and Sharing

    -

    Information about all Popcode users is collected on our behalf by our business partners in order to provide the makers of Popcode with insights into usage of the product. This information is not explicitly linked to an individual user’s identity, but does contain data which might allow a user’s personal identity to be ascertained (e.g. IP address).

    +

    + Information about all Popcode users is collected on our behalf by our + business partners in order to provide the makers of Popcode with insights + into usage of the product. This information is not explicitly linked to an + individual user’s identity, but does contain data which might allow a + user’s personal identity to be ascertained (e.g. IP address). +

    -

    For users who choose to register for accounts on Popcode, we store basic profile information (name, email address) in a database we control. This information is used purely for identifying user accounts. No unsolicited email will ever be sent. This information will under no circumstances ever be shared with a third party. Usage of Popcode does not require creating an account.

    +

    + For users who choose to register for accounts on Popcode, we store basic + profile information (name, email address) in a database we control. This + information is used purely for identifying user accounts. No unsolicited + email will ever be sent. This information will under no circumstances ever + be shared with a third party. Usage of Popcode does not require creating + an account. +

    -

    Some of our business partners may use cookies on our site (for example, collecting information about how the site is used). However, we have no access to or control over these cookies.

    +

    + Some of our business partners may use cookies on our site (for example, + collecting information about how the site is used). However, we have no + access to or control over these cookies. +

    -

    If you contact us regarding a problem with our product, we may access information in your account in order to help you resolve the problem.

    +

    + If you contact us regarding a problem with our product, we may access + information in your account in order to help you resolve the problem. +

    Your Access to and Control Over Information

    -

    You can do the following at any time by contacting us via the email address given at the bottom of this notice:

    +

    + You can do the following at any time by contacting us via the email + address given at the bottom of this notice: +

    • See what data we have about you, if any.
    • @@ -33,18 +67,44 @@

      Your Access to and Control Over Information

    • Express any concern you have about our use of your data.
    -

    Security

    +

    Security

    -

    All first-party data that we retain is stored in a cloud database service operated by Google, a reputable vendor with strong security practices.

    +

    + All first-party data that we retain is stored in a cloud database service + operated by Google, a reputable vendor with strong security practices. +

    -

    Wherever we collect your information, that information is encrypted and transmitted in a secure way. You can verify this by looking for a lock icon in the address bar and looking for "https" at the beginning of the address of the Web page.

    +

    + Wherever we collect your information, that information is encrypted and + transmitted in a secure way. You can verify this by looking for a lock + icon in the address bar and looking for "https" at the beginning of the + address of the Web page. +

    -

    While we use encryption to protect sensitive information transmitted online, we also protect your information offline. Only people who need the information to perform a specific job (for example, troubleshooting a bug) are granted access to personally identifiable information.

    +

    + While we use encryption to protect sensitive information transmitted + online, we also protect your information offline. Only people who need the + information to perform a specific job (for example, troubleshooting a bug) + are granted access to personally identifiable information. +

    Links

    -

    This website contains links to other sites. Please be aware that we are not responsible for the content or privacy practices of such other sites. We encourage our users to be aware when they leave our site and to read the privacy statements of any other site that collects personally identifiable information.

    +

    + This website contains links to other sites. Please be aware that we are + not responsible for the content or privacy practices of such other sites. + We encourage our users to be aware when they leave our site and to read + the privacy statements of any other site that collects personally + identifiable information. +

    -

    If you feel that we are not abiding by this privacy policy, you should contact us immediately via email at popcode.editor@gmail.com.

    +

    + If you feel that we are not abiding by this privacy policy, you should + contact us immediately via email at + popcode.editor@gmail.com. +

    diff --git a/src/util/ExtendableError.js b/src/util/ExtendableError.js index 873c5fd019..f185bd1ee4 100644 --- a/src/util/ExtendableError.js +++ b/src/util/ExtendableError.js @@ -1,7 +1,7 @@ export default function ExtendableError(message) { this.name = this.constructor.name; this.message = message; - this.stack = (new Error(message)).stack; + this.stack = new Error(message).stack; } ExtendableError.prototype = Object.create(Error.prototype); diff --git a/src/util/ace.js b/src/util/ace.js index a83b521963..f3e95db31a 100644 --- a/src/util/ace.js +++ b/src/util/ace.js @@ -5,8 +5,9 @@ function disableAutoClosing(editor) { } export function inheritFontStylesFromParentElement(editor) { - const computedStyle = - getComputedStyle(editor.renderer.getContainerElement().parentElement); + const computedStyle = getComputedStyle( + editor.renderer.getContainerElement().parentElement, + ); editor.setOptions({ fontFamily: computedStyle.getPropertyValue('font-family'), fontSize: computedStyle.getPropertyValue('font-size'), diff --git a/src/util/beautifySource.js b/src/util/beautifySource.js index 7c1535fa20..68d6c2f694 100644 --- a/src/util/beautifySource.js +++ b/src/util/beautifySource.js @@ -30,10 +30,12 @@ const BEAUTIFY_SETTINGS = { const importingBeautify = importBeautify(); async function importBeautify() { - return retryingFailedImports(() => import( - /* webpackChunkName: "mainAsync" */ - 'js-beautify' // eslint-disable-line comma-dangle - )); + return retryingFailedImports(() => + import( + /* webpackChunkName: "mainAsync" */ + 'js-beautify' + ), + ); } export default async function beautifySource(code, mode) { @@ -51,4 +53,3 @@ function formatCode(Beautify, code, mode) { } throw new Error(`could not format code of type ${mode}`); } - diff --git a/src/util/compileProject.js b/src/util/compileProject.js index 30392309f3..6c98ff9e5b 100644 --- a/src/util/compileProject.js +++ b/src/util/compileProject.js @@ -24,8 +24,7 @@ async function downloadScript() { const responses = await Promise.all( map(document.querySelectorAll('.preview-bundle'), el => fetch(el.src)), ); - const scripts = - await Promise.all(responses.map(response => response.text())); + const scripts = await Promise.all(responses.map(response => response.text())); return scripts.join('\n'); } @@ -54,8 +53,9 @@ function ensureDocumentElement(doc) { } async function attachLibraries(doc, project) { - const enabledLibrariesWithDependencies = - await librariesWithDependencies(project.enabledLibraries); + const enabledLibrariesWithDependencies = await librariesWithDependencies( + project.enabledLibraries, + ); if (isEmpty(enabledLibrariesWithDependencies)) { return; @@ -97,7 +97,6 @@ function attachJavascriptLibrary(doc, javascript) { const scriptTag = doc.createElement('script'); const javascriptText = String(javascript); scriptTag.innerHTML = javascriptText.replace(/<\/script>/gu, '<\\/script>'); - // eslint-disable-next-line prefer-destructuring const firstScriptTag = doc.scripts[0]; if (firstScriptTag) { firstScriptTag.parentNode.insertBefore(scriptTag, firstScriptTag); @@ -113,8 +112,9 @@ async function librariesWithDependencies(libraryKeys) { const libraries = await importLibraries(); - const requestedLibraries = - libraryKeys.map(libraryKey => libraries[libraryKey]); + const requestedLibraries = libraryKeys.map( + libraryKey => libraries[libraryKey], + ); const dependencies = compact(flatMap(requestedLibraries, 'dependsOn')); @@ -124,17 +124,18 @@ async function librariesWithDependencies(libraryKeys) { } async function importLibraries() { - return retryingFailedImports(() => import( - /* webpackChunkName: "previewLibraries" */ - '../config/libraryAssets' // eslint-disable-line comma-dangle - )); + return retryingFailedImports(() => + import( + /* webpackChunkName: "previewLibraries" */ + '../config/libraryAssets' + ), + ); } function addBase(doc) { const {head} = doc; const baseTag = doc.createElement('base'); baseTag.target = '_top'; - // eslint-disable-next-line prefer-destructuring const firstChild = head.childNodes[0]; if (firstChild) { head.insertBefore(baseTag, firstChild); @@ -167,10 +168,10 @@ async function addJavascript( let source = `\n${sourceDelimiter}\n${javascript}`; if (breakLoops) { - const {'default': loopBreaker} = await retryingFailedImports( - () => import( + const {default: loopBreaker} = await retryingFailedImports(() => + import( /* webpackChunkName: "mainAsync" */ - 'loop-breaker' // eslint-disable-line comma-dangle + 'loop-breaker' ), ); source = loopBreaker(source); @@ -185,10 +186,7 @@ export function generateTextPreview(project) { return (title || '').trim(); } -export default async function compileProject( - project, - {isInlinePreview} = {}, -) { +export default async function compileProject(project, {isInlinePreview} = {}) { const doc = constructDocument(project); await attachLibraries(doc, project); diff --git a/src/util/errorUtils.js b/src/util/errorUtils.js index 89fa3d4aea..2cda6c7009 100644 --- a/src/util/errorUtils.js +++ b/src/util/errorUtils.js @@ -1,16 +1,12 @@ import normalizeError from './normalizeError'; export function noValidationErrors(errors) { - return !errors.find( - list => list.get('items').find( - error => error.get('phase') === 'validation', - ), + return !errors.find(list => + list.get('items').find(error => error.get('phase') === 'validation'), ); } export function createError(error) { const ErrorConstructor = window[error.name] || Error; - return normalizeError( - new ErrorConstructor(error.message), - ); + return normalizeError(new ErrorConstructor(error.message)); } diff --git a/src/util/i18nFormatting.js b/src/util/i18nFormatting.js index bd31db87ec..c311ea1ada 100644 --- a/src/util/i18nFormatting.js +++ b/src/util/i18nFormatting.js @@ -17,6 +17,7 @@ function getVariationOfAOrAn(value) { } export default function applyCustomI18nFormatters(value, format) { - return format.split('|').reduce((acc, val) => - get(formatters, val, identity)(acc), value); + return format + .split('|') + .reduce((acc, val) => get(formatters, val, identity)(acc), value); } diff --git a/src/util/javascript.js b/src/util/javascript.js index 840859b6ca..6d6ccef38e 100644 --- a/src/util/javascript.js +++ b/src/util/javascript.js @@ -11,6 +11,8 @@ function tryParse(javascript) { export function hasExpressionStatement(javascript) { const maybeParsed = tryParse(javascript); - return Boolean(maybeParsed && find(maybeParsed.body, - ({type}) => type === 'ExpressionStatement')); + return Boolean( + maybeParsed && + find(maybeParsed.body, ({type}) => type === 'ExpressionStatement'), + ); } diff --git a/src/util/markdown.js b/src/util/markdown.js index 077f0a9079..182e67b94d 100644 --- a/src/util/markdown.js +++ b/src/util/markdown.js @@ -11,16 +11,13 @@ import githubSchema from 'hast-util-sanitize/lib/github.json'; const remarkWithHighlighting = memoize(() => { const schema = Object.assign({}, githubSchema, { attributes: Object.assign({}, githubSchema.attributes, { - code: [ - ...(githubSchema.attributes.code || []), - 'className', - ], + code: [...(githubSchema.attributes.code || []), 'className'], }), }); - return remark(). - use(externalLinks). - use(remarkReact, { + return remark() + .use(externalLinks) + .use(remarkReact, { sanitize: schema, remarkReactComponents: { code: remarkLowlight({css, js, xml}), diff --git a/src/util/normalizeError.js b/src/util/normalizeError.js index 4bc158989a..1beeda4d0a 100644 --- a/src/util/normalizeError.js +++ b/src/util/normalizeError.js @@ -8,7 +8,7 @@ import bowser from '../services/bowser'; const normalizers = { Chrome: { - TypeError: (message) => { + TypeError: message => { let match; match = /^(\w+) is not a function$/u.exec(message); @@ -16,8 +16,9 @@ const normalizers = { return {type: 'not-a-function', params: {name: match[1]}}; } - match = /^Cannot (read|set) property '(.+)' of (null|undefined)$/u. - exec(message); + match = /^Cannot (read|set) property '(.+)' of (null|undefined)$/u.exec( + message, + ); if (match) { return { type: `${match[1]}-property-of-${match[3]}`, @@ -30,10 +31,12 @@ const normalizers = { }, Safari: { - TypeError: (message) => { + TypeError: message => { let match; - match = /^(\w+) is not a function. \(In '\w+\(\)', '\w+' is (\w+|an instance of (\w+))\)$/u.exec(message); // eslint-disable-line max-len + match = /^(\w+) is not a function. \(In '\w+\(\)', '\w+' is (\w+|an instance of (\w+))\)$/u.exec( + message, + ); if (match) { if (match[3]) { @@ -66,7 +69,7 @@ const normalizers = { }, Firefox: { - TypeError: (message) => { + TypeError: message => { let match; match = /^(\w+) is not a function$/u.exec(message); @@ -90,7 +93,9 @@ const normalizers = { function attachMessage(normalizedError) { let context; if (!isEmpty(normalizedError.params)) { - context = `with-${keys(normalizedError.params).sort().join('-')}`; + context = `with-${keys(normalizedError.params) + .sort() + .join('-')}`; } return assign(normalizedError, { diff --git a/src/util/performWithRetries.js b/src/util/performWithRetries.js index c5ff8cdf3c..81812305a5 100644 --- a/src/util/performWithRetries.js +++ b/src/util/performWithRetries.js @@ -7,17 +7,21 @@ export default function performWithRetries( options = {}, ) { return promiseRetry( - retry => perform().catch((error) => { - if (shouldRetryFn(error.message)) { - return retry(error); - } - return Promise.reject(error); - }), - assign({ - retries: 5, - factor: 2, - minTimeout: 1000, - maxTimeout: 10000, - }, options), + retry => + perform().catch(error => { + if (shouldRetryFn(error.message)) { + return retry(error); + } + return Promise.reject(error); + }), + assign( + { + retries: 5, + factor: 2, + minTimeout: 1000, + maxTimeout: 10000, + }, + options, + ), ); } diff --git a/src/validations/Validator.js b/src/validations/Validator.js index fcd505e897..94f2c32e1a 100644 --- a/src/validations/Validator.js +++ b/src/validations/Validator.js @@ -16,10 +16,7 @@ class Validator { async getAnnotations() { const errors = await this.getRawErrors(); - return compact(map( - errors, - this._convertErrorToAnnotation.bind(this), - )); + return compact(map(errors, this._convertErrorToAnnotation.bind(this))); } mapError(rawError) { @@ -49,7 +46,10 @@ class Validator { const location = this.locationForError(rawError); return assign({}, location, error, { - text: remark().use(stripMarkdown).processSync(message).toString(), + text: remark() + .use(stripMarkdown) + .processSync(message) + .toString(), raw: message, type: 'error', }); diff --git a/src/validations/css.js b/src/validations/css.js index 62e2be3350..cb7bacc29f 100644 --- a/src/validations/css.js +++ b/src/validations/css.js @@ -3,8 +3,9 @@ import validateWithCss from './css/css'; import validateWithPrettyCSS from './css/prettycss'; import validateWithStyleLint from './css/stylelint'; -export default source => mergeValidations([ - validateWithCss(source), - validateWithPrettyCSS(source), - validateWithStyleLint(source), -]); +export default source => + mergeValidations([ + validateWithCss(source), + validateWithPrettyCSS(source), + validateWithStyleLint(source), + ]); diff --git a/src/validations/css/css.js b/src/validations/css/css.js index aacdcb7388..6f6a072012 100644 --- a/src/validations/css/css.js +++ b/src/validations/css/css.js @@ -3,9 +3,9 @@ import css from 'css'; import Validator from '../Validator'; const errorMap = { - 'missing \'{\'': () => ({reason: 'missing-opening-curly'}), + "missing '{'": () => ({reason: 'missing-opening-curly'}), - 'property missing \':\'': () => ({ + "property missing ':'": () => ({ reason: 'property-missing-colon', suppresses: ['invalid-token', 'missing-closing-curly'], }), diff --git a/src/validations/css/prettycss.js b/src/validations/css/prettycss.js index a24a3e58ac..342bacec74 100644 --- a/src/validations/css/prettycss.js +++ b/src/validations/css/prettycss.js @@ -4,8 +4,7 @@ import endsWith from 'lodash-es/endsWith'; import Validator from '../Validator'; -const RADIAL_GRADIENT_EXPR = - /^(?:(?:-(?:ms|moz|o|webkit)-)?radial-gradient|-webkit-gradient)/u; +const RADIAL_GRADIENT_EXPR = /^(?:(?:-(?:ms|moz|o|webkit)-)?radial-gradient|-webkit-gradient)/u; const FILTER_VALUE_EXPR = // eslint-disable-next-line require-unicode-regexp @@ -26,8 +25,10 @@ const FILTER_VALUE_EXPR = ); function isIncorrectlyRejectedValue(value) { - return isIncorrectlyRejectedRadialGradientValue(value) || - isIncorrectlyRejectedFilterValue(value); + return ( + isIncorrectlyRejectedRadialGradientValue(value) || + isIncorrectlyRejectedFilterValue(value) + ); } function isIncorrectlyRejectedRadialGradientValue(value) { @@ -38,7 +39,7 @@ function isIncorrectlyRejectedFilterValue(value) { } const errorMap = { - 'block-expected': (error) => { + 'block-expected': error => { const tokenType = error.token.type; const token = error.token.content; @@ -77,10 +78,10 @@ const errorMap = { } } - return ({ + return { reason: 'extra-tokens-after-value', payload: {token: errorToken.content}, - }); + }; }, 'illegal-token-after-combinator': () => ({ @@ -97,7 +98,7 @@ const errorMap = { ], }), - 'invalid-value': (error) => { + 'invalid-value': error => { if (isIncorrectlyRejectedValue(error.token.content)) { return null; } diff --git a/src/validations/html.js b/src/validations/html.js index 24ef5d032d..e38b35c4ad 100644 --- a/src/validations/html.js +++ b/src/validations/html.js @@ -6,9 +6,10 @@ import validateWithHtmllint from './html/htmllint'; import validateWithRules from './html/rules'; import validateWithSlowparse from './html/slowparse'; -export default source => mergeValidations([ - validateWithHtmlInspector(source), - validateWithHtmllint(source), - validateWithSlowparse(trim(source)), - validateWithRules(source), -]); +export default source => + mergeValidations([ + validateWithHtmlInspector(source), + validateWithHtmllint(source), + validateWithSlowparse(trim(source)), + validateWithRules(source), + ]); diff --git a/src/validations/html/htmlInspector.js b/src/validations/html/htmlInspector.js index 749ab2d400..e6a962f362 100644 --- a/src/validations/html/htmlInspector.js +++ b/src/validations/html/htmlInspector.js @@ -18,7 +18,7 @@ const specialCases = { }; const errorMap = { - 'validate-element-location': (error) => { + 'validate-element-location': error => { const tag = error.context.tagName.toLowerCase(); const parent = error.context.parentNode.tagName.toLowerCase(); if (specialCases[tag]) { @@ -40,7 +40,7 @@ const errorMap = { }, }; }, - 'text-elements-as-list-children': (error) => { + 'text-elements-as-list-children': error => { const tag = error.context.tagName.toLowerCase(); let requiredChild = 'li'; @@ -67,10 +67,7 @@ function noListsWithTextChildrenValidator(listener, reporter) { ) { for (const node of domElement.childNodes) { const textContent = trim(node.textContent); - if ( - node.nodeType === Node.TEXT_NODE && - textContent.length > 0 - ) { + if (node.nodeType === Node.TEXT_NODE && textContent.length > 0) { reporter.warn( 'text-elements-as-list-children', textContent, @@ -99,7 +96,7 @@ class HtmlInspectorValidator extends Validator { return Promise.resolve([]); } - return new Promise((resolve) => { + return new Promise(resolve => { HTMLInspector.inspect({ domRoot: this._doc.documentElement, useRules: ['validate-element-location', 'validate-list-children'], diff --git a/src/validations/html/htmllint.js b/src/validations/html/htmllint.js index cc1cde7a04..3831bda2e9 100644 --- a/src/validations/html/htmllint.js +++ b/src/validations/html/htmllint.js @@ -6,7 +6,7 @@ import reduce from 'lodash-es/reduce'; import Validator from '../Validator'; const errorMap = { - E001: (error) => { + E001: error => { switch (error.data.attribute.toLowerCase()) { case 'align': return {reason: 'banned-attributes.align'}; @@ -61,8 +61,7 @@ const errorMap = { E018: (error, source) => { const lines = source.split('\n'); const tagNameExpr = /(.*?)\s*\/>/u; - const [, tag] = - tagNameExpr.exec(lines[error.line - 1].slice(error.column)); + const [, tag] = tagNameExpr.exec(lines[error.line - 1].slice(error.column)); return { reason: 'self-closing-tag', @@ -123,15 +122,7 @@ const htmlLintOptions = { 'html-valid-content-model': true, 'id-no-dup': true, 'img-req-src': true, - 'tag-bans': [ - 'b', - 'big', - 'center', - 'font', - 'i', - 'tt', - 'strike', - ], + 'tag-bans': ['b', 'big', 'center', 'font', 'i', 'tt', 'strike'], 'tag-name-match': true, 'tag-name-lowercase': true, 'tag-self-close': 'never', diff --git a/src/validations/html/rules/MismatchedTag.js b/src/validations/html/rules/MismatchedTag.js index 1a7113f757..b9d5c2a15e 100644 --- a/src/validations/html/rules/MismatchedTag.js +++ b/src/validations/html/rules/MismatchedTag.js @@ -69,7 +69,7 @@ export default class MismatchedTag { } } - * done() { + *done() { for (const mismatches of this._mismatchStacksByOpenName.values()) { for (const {openTag, closeTag} of mismatches) { yield {code: Code.UNCLOSED_TAG, openTag, closeTag}; diff --git a/src/validations/html/rules/NodeOutsideBody.js b/src/validations/html/rules/NodeOutsideBody.js index 964e8c45ae..c011989283 100644 --- a/src/validations/html/rules/NodeOutsideBody.js +++ b/src/validations/html/rules/NodeOutsideBody.js @@ -44,11 +44,12 @@ export default class NodeOutsideBody { text(location, text) { const trimmedText = text.trim(); - if (trimmedText && ( - this._isTopLevel() || - this._isInsideHtmlTag() || - this._isDirectChildOfHead() - )) { + if ( + trimmedText && + (this._isTopLevel() || + this._isInsideHtmlTag() || + this._isDirectChildOfHead()) + ) { const matchingWhitespaces = text.match(/^(\s+)/gu); if (matchingWhitespaces) { @@ -72,17 +73,20 @@ export default class NodeOutsideBody { } _isInsideHtmlTag() { - return this._openTagStack.length === 1 && - this._openTagStack[0].name === 'html'; + return ( + this._openTagStack.length === 1 && this._openTagStack[0].name === 'html' + ); } _isDirectChildOfHead() { - return this._openTagStack.length === 2 && + return ( + this._openTagStack.length === 2 && this._openTagStack[0].name === 'html' && - this._openTagStack[1].name === 'head'; + this._openTagStack[1].name === 'head' + ); } - * done() { + *done() { for (const {location} of this._invalidTextLocations) { yield { code: Code.INVALID_TEXT_OUTSIDE_BODY, diff --git a/src/validations/html/rules/index.js b/src/validations/html/rules/index.js index 0444ba11e4..c6b89ce4e3 100644 --- a/src/validations/html/rules/index.js +++ b/src/validations/html/rules/index.js @@ -43,10 +43,9 @@ class RuleValidator extends Validator { } async getRawErrors() { - return Array.from(await runRules([ - new MismatchedTag(), - new NodeOutsideBody(), - ], this.source)); + return Array.from( + await runRules([new MismatchedTag(), new NodeOutsideBody()], this.source), + ); } locationForError(error) { diff --git a/src/validations/html/runRules.js b/src/validations/html/runRules.js index 29933f4877..e01c6adb44 100644 --- a/src/validations/html/runRules.js +++ b/src/validations/html/runRules.js @@ -13,14 +13,10 @@ import voidElements from 'void-elements'; // to take in close tags export default (rules, source) => { const parser = new SAXParser({sourceCodeLocationInfo: true}); - return new Promise((resolve) => { + return new Promise(resolve => { parser.on( 'startTag', - ({ - tagName, - selfClosing, - sourceCodeLocation: {startLine, startCol}, - }) => { + ({tagName, selfClosing, sourceCodeLocation: {startLine, startCol}}) => { for (const rule of rules) { if (rule.openTag && !selfClosing && !(tagName in voidElements)) { rule.openTag( @@ -41,23 +37,22 @@ export default (rules, source) => { } }, ); - parser.on( - 'text', - ({text, sourceCodeLocation: {startLine, startCol}}) => { - for (const rule of rules) { - if (rule.text) { - rule.text({row: startLine - 1, column: startCol - 1}, text); - } + parser.on('text', ({text, sourceCodeLocation: {startLine, startCol}}) => { + for (const rule of rules) { + if (rule.text) { + rule.text({row: startLine - 1, column: startCol - 1}, text); } - }, - ); + } + }); parser.write(source); parser.end(() => { - resolve(function* getRules() { - for (const rule of rules) { - yield* rule.done(); - } - }()); + resolve( + (function* getRules() { + for (const rule of rules) { + yield* rule.done(); + } + })(), + ); }); }); }; diff --git a/src/validations/html/slowparse.js b/src/validations/html/slowparse.js index 5f117ffc63..94333073da 100644 --- a/src/validations/html/slowparse.js +++ b/src/validations/html/slowparse.js @@ -112,9 +112,9 @@ function emptyTitleElementDetector(_, root) { const html = findChildNode(root, 'HTML'); const head = html ? findChildNode(html, 'HEAD') : null; const title = head ? findChildNode(head, 'TITLE') : null; - return (title && !title.childNodes.length) ? - {type: 'EMPTY_TITLE_ELEMENT', cursor: title.parseInfo.openTag.end} : - null; + return title && !title.childNodes.length + ? {type: 'EMPTY_TITLE_ELEMENT', cursor: title.parseInfo.openTag.end} + : null; } const errorDetectors = [emptyTitleElementDetector]; diff --git a/src/validations/javascript.js b/src/validations/javascript.js index 01974e9f06..1d1cdaca0c 100644 --- a/src/validations/javascript.js +++ b/src/validations/javascript.js @@ -2,7 +2,8 @@ import mergeValidations from './mergeValidations'; import validateWithEsprima from './javascript/esprima'; import validateWithJSHint from './javascript/jshint'; -export default (source, analyzer) => mergeValidations([ - validateWithEsprima(source), - validateWithJSHint(source, analyzer), -]); +export default (source, analyzer) => + mergeValidations([ + validateWithEsprima(source), + validateWithJSHint(source, analyzer), + ]); diff --git a/src/validations/javascript/esprima.js b/src/validations/javascript/esprima.js index 74204103d6..69150b57e7 100644 --- a/src/validations/javascript/esprima.js +++ b/src/validations/javascript/esprima.js @@ -49,7 +49,7 @@ const errorMap = { break; } - return ({ + return { reason: `${message}`, payload: {value: token.value}, suppresses: [ @@ -59,7 +59,7 @@ const errorMap = { 'closing-match', 'strict-operators.custom-case', ], - }); + }; }, 'Unexpected end of input': () => ({reason: 'end-of-input'}), @@ -68,7 +68,7 @@ const errorMap = { }; function findTokenForError(error, tokens) { - return find(tokens, (token) => { + return find(tokens, token => { const [startLocation, endLocation] = token.range; return inRange(error.index, startLocation, endLocation + 1); }); @@ -84,10 +84,7 @@ class EsprimaValidator extends Validator { parse(this.source); } catch (error) { try { - const tokens = tokenize( - this.source, - {range: true, comment: true}, - ); + const tokens = tokenize(this.source, {range: true, comment: true}); const token = findTokenForError(error, tokens); return [{error, token}]; } catch (tokenizeError) { diff --git a/src/validations/javascript/jshint.js b/src/validations/javascript/jshint.js index e9df03832c..cbd9dc7328 100644 --- a/src/validations/javascript/jshint.js +++ b/src/validations/javascript/jshint.js @@ -26,7 +26,7 @@ const match = { '{': '}', '[': ']', '(': ')', - '\'': '\'', + "'": "'", '"': '"', }; @@ -88,7 +88,7 @@ const errorMap = { suppresses: ['expected-identifier', 'tokenize-error', 'missing-semicolon'], }), - W116: (error) => { + W116: error => { if (error.a === '===' && error.b === '==') { return {reason: 'strict-operators.equal'}; } @@ -111,13 +111,12 @@ const errorMap = { }; }, - W117: (error) => { + W117: error => { const identifier = error.a; const providingLibrary = find( libraries, - library => - library.predefined && includes(library.predefined, identifier), + library => library.predefined && includes(library.predefined, identifier), ); if (providingLibrary) { @@ -155,7 +154,7 @@ class JsHintValidator extends Validator { options.undef = false; } - enabledLibraries.forEach((libraryKey) => { + enabledLibraries.forEach(libraryKey => { if (!(libraryKey in libraries)) { return; } @@ -163,8 +162,7 @@ class JsHintValidator extends Validator { const library = libraries[libraryKey]; if (library.predefined) { - options.predef = - concat(options.predef, library.predefined); + options.predef = concat(options.predef, library.predefined); } }); diff --git a/src/validations/mergeValidations.js b/src/validations/mergeValidations.js index b1589d3dc3..b03d7b5eb6 100644 --- a/src/validations/mergeValidations.js +++ b/src/validations/mergeValidations.js @@ -8,10 +8,7 @@ import omit from 'lodash-es/omit'; function filterErrors(errors) { const groupedErrors = groupBy(errors, 'reason'); - const suppressedTypes = flatMap( - flatten(values(groupedErrors)), - 'suppresses', - ); + const suppressedTypes = flatMap(flatten(values(groupedErrors)), 'suppresses'); return flatten(values(omit(groupedErrors, suppressedTypes))); } diff --git a/test/helpers/Scenario.js b/test/helpers/Scenario.js index 8112f90ffc..24739341e9 100644 --- a/test/helpers/Scenario.js +++ b/test/helpers/Scenario.js @@ -1,11 +1,6 @@ import reduce from '../../src/reducers'; -import { - projectCreated, -} from '../../src/actions/projects'; -import { - identityLinked, - userAuthenticated, -} from '../../src/actions/user'; +import {projectCreated} from '../../src/actions/projects'; +import {identityLinked, userAuthenticated} from '../../src/actions/user'; import Analyzer from '../../src/analyzers'; import {githubCredential, userCredential} from './factory'; @@ -24,18 +19,20 @@ export default class Scenario { authGitHub() { const credential = githubCredential(); - this._reduce(identityLinked( - { - providerData: [ - { - providerId: 'github.com', - displayName: 'popcode user', - avatarURL: 'https://github.com/popcode.jpg', - }, - ], - }, - credential, - )); + this._reduce( + identityLinked( + { + providerData: [ + { + providerId: 'github.com', + displayName: 'popcode user', + avatarURL: 'https://github.com/popcode.jpg', + }, + ], + }, + credential, + ), + ); return credential; } @@ -55,4 +52,3 @@ export default class Scenario { this.state = reduce(this.state, action); } } - diff --git a/test/helpers/factory.js b/test/helpers/factory.js index 695271cbf9..72351587c3 100644 --- a/test/helpers/factory.js +++ b/test/helpers/factory.js @@ -2,7 +2,11 @@ import defaultsDeep from 'lodash-es/defaultsDeep'; import isNil from 'lodash-es/isNil'; export function gistData({ - html, css, javascript, enabledLibraries, hiddenUIComponents, + html, + css, + javascript, + enabledLibraries, + hiddenUIComponents, } = {}) { const files = []; if (!isNil(html)) { @@ -28,10 +32,7 @@ export function gistData({ return {files}; } -export function userCredential({ - user: userIn, - credential: credentialIn, -} = {}) { +export function userCredential({user: userIn, credential: credentialIn} = {}) { return { user: user(userIn), credential: credential(credentialIn), diff --git a/test/helpers/i18nFactory.js b/test/helpers/i18nFactory.js index 0411b58108..2753ed87c3 100644 --- a/test/helpers/i18nFactory.js +++ b/test/helpers/i18nFactory.js @@ -8,7 +8,7 @@ const enTestResourceData = { 'key-with-an-format': 'string with {{tag, en-handle-an}} {{tag}}', 'key-with-capitalize-format': '{{tag, capitalize}}', 'key-with-multiple-formats': - 'string with {{tag, en-handle-an|capitalize}} {{tag}}', + 'string with {{tag, en-handle-an|capitalize}} {{tag}}', 'key-invalid-formatter': '{{tag, invalid}}', 'key-invalid-and-valid-formatter': '{{tag, invalid|capitalize}}', }; diff --git a/test/helpers/localizationTest.js b/test/helpers/localizationTest.js index e0e572b805..20f5bc8753 100644 --- a/test/helpers/localizationTest.js +++ b/test/helpers/localizationTest.js @@ -1,15 +1,11 @@ -export default (instance, key, options, expected, description) => - (assert) => { - const actual = instance.t(key, options); - let message = `Expected:\n"${expected}",\n\nActual:\n"${actual}"`; - if (description) { - message = `${description}\n\n${message}`; - } +export default (instance, key, options, expected, description) => assert => { + const actual = instance.t(key, options); + let message = `Expected:\n"${expected}",\n\nActual:\n"${actual}"`; + if (description) { + message = `${description}\n\n${message}`; + } - assert.ok( - actual === expected, - message, - ); + assert.ok(actual === expected, message); - assert.end(); - }; + assert.end(); +}; diff --git a/test/helpers/reducerTest.js b/test/helpers/reducerTest.js index 8c7047c4cd..6e3975db65 100644 --- a/test/helpers/reducerTest.js +++ b/test/helpers/reducerTest.js @@ -1,17 +1,19 @@ import Immutable from 'immutable'; -export default (reducer, stateBefore, action, stateAfter, description) => - (assert) => { - const expected = stateAfter; - const actual = reducer(stateBefore, action()); - let message = `Expected:\n${expected}\n\nActual:\n${actual}`; - if (description) { - message = `${description}\n\n${message}`; - } - assert.ok( - Immutable.is(expected, actual), - message, - ); +export default ( + reducer, + stateBefore, + action, + stateAfter, + description, +) => assert => { + const expected = stateAfter; + const actual = reducer(stateBefore, action()); + let message = `Expected:\n${expected}\n\nActual:\n${actual}`; + if (description) { + message = `${description}\n\n${message}`; + } + assert.ok(Immutable.is(expected, actual), message); - assert.end(); - }; + assert.end(); +}; diff --git a/test/helpers/referenceStates.js b/test/helpers/referenceStates.js index a5c99de38a..5ce932d75d 100644 --- a/test/helpers/referenceStates.js +++ b/test/helpers/referenceStates.js @@ -60,31 +60,35 @@ export const googleClassroom = { }), withCourses: new GoogleClassroom({ courses: new RemoteCollection({ - items: new Map({10800902048: new Course({ - alternateLink: 'http://classroom.google.com/c/MTA4MDA5MDIwNDha', - courseState: 'ACTIVE', - creationTime: '2018-01-22T22:16:25.726Z', - descriptionHeading: '2018-2019 Program Manager Tech Training', - guardiansEnabled: true, - id: '10800902048', - name: '2018-2019 Sample Class', - updateTime: '2018-10-01T18:11:58.432Z', - })}), + items: new Map({ + 10800902048: new Course({ + alternateLink: 'http://classroom.google.com/c/MTA4MDA5MDIwNDha', + courseState: 'ACTIVE', + creationTime: '2018-01-22T22:16:25.726Z', + descriptionHeading: '2018-2019 Program Manager Tech Training', + guardiansEnabled: true, + id: '10800902048', + name: '2018-2019 Sample Class', + updateTime: '2018-10-01T18:11:58.432Z', + }), + }), isFullyLoaded: false, }), }), withCoursesAndFullyLoaded: new GoogleClassroom({ courses: new RemoteCollection({ - items: new Map({10800902048: new Course({ - alternateLink: 'http://classroom.google.com/c/MTA4MDA5MDIwNDha', - courseState: 'ACTIVE', - creationTime: '2018-01-22T22:16:25.726Z', - descriptionHeading: '2018-2019 Program Manager Tech Training', - guardiansEnabled: true, - id: '10800902048', - name: '2018-2019 Sample Class', - updateTime: '2018-10-01T18:11:58.432Z', - })}), + items: new Map({ + 10800902048: new Course({ + alternateLink: 'http://classroom.google.com/c/MTA4MDA5MDIwNDha', + courseState: 'ACTIVE', + creationTime: '2018-01-22T22:16:25.726Z', + descriptionHeading: '2018-2019 Program Manager Tech Training', + guardiansEnabled: true, + id: '10800902048', + name: '2018-2019 Sample Class', + updateTime: '2018-10-01T18:11:58.432Z', + }), + }), isFullyLoaded: true, }), }), diff --git a/test/helpers/testValidatorAcceptance.js b/test/helpers/testValidatorAcceptance.js index 61383ee407..94c7bbb9ed 100644 --- a/test/helpers/testValidatorAcceptance.js +++ b/test/helpers/testValidatorAcceptance.js @@ -3,10 +3,9 @@ import acceptance from '../data/acceptance.json'; import validationTest from './validationTest'; export default function testValidatorAcceptance(validator, language) { - return (t) => { - acceptance[language].forEach( - source => t.test(`Acceptance - ${language}`, - validationTest(source, validator)), + return t => { + acceptance[language].forEach(source => + t.test(`Acceptance - ${language}`, validationTest(source, validator)), ); }; } diff --git a/test/helpers/validationTest.js b/test/helpers/validationTest.js index 268f9a4b66..c64f3c484a 100644 --- a/test/helpers/validationTest.js +++ b/test/helpers/validationTest.js @@ -3,13 +3,12 @@ import orderBy from 'lodash-es/orderBy'; import pick from 'lodash-es/pick'; export default function validationTest(input, validate, ...expectedErrors) { - return async(assert) => { + return async assert => { try { const errors = await validate(input); assert.deepEqual( - map( - orderBy(errors, ['reason', 'row']), - error => pick(error, ['reason', 'row', 'payload']), + map(orderBy(errors, ['reason', 'row']), error => + pick(error, ['reason', 'row', 'payload']), ), orderBy(expectedErrors, ['reason', 'row']), ); diff --git a/test/unit/Analyzer.js b/test/unit/Analyzer.js index 372ba4c36e..11753184e7 100644 --- a/test/unit/Analyzer.js +++ b/test/unit/Analyzer.js @@ -3,7 +3,7 @@ import test from 'tape-catch'; import Analyzer from '../../src/analyzers'; import {Project} from '../../src/records'; -test('no script tag', (assert) => { +test('no script tag', assert => { const html = '

    Some harmless html

    '; const currentProject = Project.fromJS({sources: {html}}).toJS(); const analyzer = new Analyzer(currentProject); @@ -11,7 +11,7 @@ test('no script tag', (assert) => { assert.end(); }); -test('