Skip to content

Commit

Permalink
Init perseus-score and move answer-types and perseus-types (#2086)
Browse files Browse the repository at this point in the history
## Summary:
Part of LEMS-2737

This PR is to initialize a new subpackage: `perseus-score`

To prove that the package was working, I decided to move `answer-types.ts` from `perseus` to `perseus-score`. This resulted in a couple of side-effects (as a result of the fact that `perseus-score` cannot import from `perseus`):

1. I needed to move `util/math.ts` from `perseus` to `kmath`
2. `math.ts` needed something from `perseus-types.ts` which means I needed to go ahead and move that from `perseus` to `perseus-core` (and per Jeremy's request I renamed `perseus-types.ts` to `data-schema.ts`)
3. Probably 90%+ of the files changed are because of the `perseus-types.ts` move
4. `answer-types.ts` needed access to `strings.ts` which is a special export from `perseus`, so I had to refactor `answer-types.ts` to use error placeholders that could get mapped to strings when being displayed to learners.

Issue: LEMS-2737

## Test plan:
- Make sure widgets that use `answer-types.ts` still work
  - Expression
  - InputNumber
  - Matrix
  - NumericInput
  - Table
- Make sure user-facing errors in those widgets still work
- I dunno, it's a big change; everything should still work

Author: handeyeco

Reviewers: handeyeco, jeremywiebe

Required Reviewers:

Approved By: jeremywiebe

Checks: ✅ Cypress (ubuntu-latest, 20.x), ✅ Publish npm snapshot (ubuntu-latest, 20.x), ✅ Check for .changeset entries for all changed files (ubuntu-latest, 20.x), ✅ Check builds for changes in size (ubuntu-latest, 20.x), ✅ Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x), ✅ Publish Storybook to Chromatic (ubuntu-latest, 20.x)

Pull Request URL: #2086
  • Loading branch information
handeyeco authored Jan 10, 2025
1 parent 5ca79ea commit bc3d955
Show file tree
Hide file tree
Showing 249 changed files with 557 additions and 409 deletions.
10 changes: 10 additions & 0 deletions .changeset/twelve-timers-pay.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
"@khanacademy/perseus": major
"@khanacademy/perseus-score": major
"@khanacademy/kmath": minor
"@khanacademy/perseus-core": minor
"@khanacademy/perseus-dev-ui": patch
"@khanacademy/perseus-editor": patch
---

Init perseus-score, move AnswerTypes from perseus to perseus-score, move perseus-types in perseus to data-schema in perseus-core
2 changes: 1 addition & 1 deletion dev/flipbook.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import type {
PerseusScore,
PerseusWidget,
} from "../packages/perseus/src";
import type {InteractiveGraphWidget} from "../packages/perseus/src/perseus-types";
import type {InteractiveGraphWidget} from "@khanacademy/perseus-core";
import type {PropsFor} from "@khanacademy/wonder-blocks-core";

import "../packages/perseus/src/styles/perseus-renderer.less";
Expand Down
2 changes: 2 additions & 0 deletions packages/kmath/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,3 +5,5 @@ export * as vector from "./vector";
export * as point from "./point";
export * as line from "./line";
export * as ray from "./ray";

export {default as KhanMath, sum} from "./math";
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,8 +1,9 @@
import {number as knumber} from "@khanacademy/kmath";
import $ from "jquery";
import _ from "underscore";

import type {MathFormat} from "../perseus-types";
import {number as knumber} from "@khanacademy/kmath";

import type {MathFormat} from "@khanacademy/perseus-core";

const KhanMath = {
// Simplify formulas before display
Expand Down
File renamed without changes.
2 changes: 2 additions & 0 deletions packages/perseus-core/src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,5 @@ export {libVersion} from "./version";

export {Errors} from "./error/errors";
export {PerseusError} from "./error/perseus-error";

export * from "./data-schema";
2 changes: 1 addition & 1 deletion packages/perseus-editor/src/components/graph-settings.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,12 @@
/**
* Used in the editors for the Grapher and Interaction widgets.
*/
import {KhanMath} from "@khanacademy/kmath";
import {
components,
interactiveSizes,
Changeable,
Dependencies,
KhanMath,
Util,
} from "@khanacademy/perseus";
import {Checkbox} from "@khanacademy/wonder-blocks-form";
Expand Down
8 changes: 8 additions & 0 deletions packages/perseus-score/.babelrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
/**
* HACK(somewhatabstract): Due to https://github.com/facebook/jest/issues/11741,
* we need to have this file, or updating inline snapshots can fail rather
* cryptically.
*
* We should remove this when jest is fixed.
*/
module.exports = require("../../config/build/babel.config");
15 changes: 15 additions & 0 deletions packages/perseus-score/.eslintrc.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
/* eslint-disable @typescript-eslint/no-require-imports */
/* eslint-disable import/no-commonjs */
const path = require("path");

module.exports = {
rules: {
"import/no-extraneous-dependencies": [
"error",
{
packageDir: [__dirname, path.join(__dirname, "../../")],
includeTypes: true,
},
],
},
};
3 changes: 3 additions & 0 deletions packages/perseus-score/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# @khanacademy/perseus-score

Logic for scoring Perseus exercises.
36 changes: 36 additions & 0 deletions packages/perseus-score/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
{
"name": "@khanacademy/perseus-score",
"description": "Perseus score",
"author": "Khan Academy",
"license": "MIT",
"version": "0.0.0",
"publishConfig": {
"access": "public"
},
"repository": {
"type": "git",
"url": "https://github.com/Khan/perseus.git",
"directory": "packages/perseus-score"
},
"bugs": {
"url": "https://github.com/Khan/perseus/issues"
},
"module": "dist/es/index.js",
"main": "dist/index.js",
"source": "src/index.ts",
"files": [
"dist"
],
"scripts": {
"prepublishOnly": "../../utils/package-pre-publish-check.sh",
"test": "bash -c 'yarn --silent --cwd \"../..\" test ${@:0} $($([[ ${@: -1} = -* ]] || [[ ${@: -1} = bash ]]) && echo $PWD)'"
},
"dependencies": {
"@khanacademy/kas": "^0.4.9",
"@khanacademy/kmath": "^0.1.24",
"@khanacademy/perseus-core": "3.0.5"
},
"devDependencies": {},
"peerDependencies": {},
"keywords": []
}
19 changes: 19 additions & 0 deletions packages/perseus-score/src/error-codes.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
const MISSING_PERCENT_ERROR = "MISSING_PERCENT_ERROR";
const NEEDS_TO_BE_SIMPLIFIED_ERROR = "NEEDS_TO_BE_SIMPLIFIED_ERROR";
const APPROXIMATED_PI_ERROR = "APPROXIMATED_PI_ERROR";
const EXTRA_SYMBOLS_ERROR = "EXTRA_SYMBOLS_ERROR";
const WRONG_CASE_ERROR = "WRONG_CASE_ERROR";
const WRONG_LETTER_ERROR = "WRONG_LETTER_ERROR";
const MULTIPLICATION_SIGN_ERROR = "MULTIPLICATION_SIGN_ERROR";

const ErrorCodes = {
MISSING_PERCENT_ERROR,
NEEDS_TO_BE_SIMPLIFIED_ERROR,
APPROXIMATED_PI_ERROR,
EXTRA_SYMBOLS_ERROR,
WRONG_CASE_ERROR,
WRONG_LETTER_ERROR,
MULTIPLICATION_SIGN_ERROR,
};

export default ErrorCodes;
3 changes: 3 additions & 0 deletions packages/perseus-score/src/index.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
export {default as KhanAnswerTypes} from "./util/answer-types";
export type {Score} from "./util/answer-types";
export {default as ErrorCodes} from "./error-codes";
Original file line number Diff line number Diff line change
@@ -1,12 +1,9 @@
import {mockStrings} from "../strings";

import khanAnswerTypes from "./answer-types";

const validateFraction = (correctAnswer: string, guess: string) => {
const validator = khanAnswerTypes.number.createValidatorFunctional(
correctAnswer,
{simplified: true},
mockStrings,
);
return validator(guess);
};
Expand Down
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
/* eslint-disable no-useless-escape */
import * as KAS from "@khanacademy/kas";
import {KhanMath} from "@khanacademy/kmath";
import {Errors, PerseusError} from "@khanacademy/perseus-core";
import $ from "jquery";
import _ from "underscore";

import KhanMath from "./math";

import type {PerseusStrings} from "../strings";
import ErrorCodes from "../error-codes";

const MAXERROR_EPSILON = Math.pow(2, -42);

Expand Down Expand Up @@ -100,7 +99,6 @@ const KhanAnswerTypes = {
createValidatorFunctional: function (
predicate: Predicate,
options: any,
strings: PerseusStrings,
): (arg1: Guess) => Score {
// Extract the options from the given solution object
options = _.extend(
Expand Down Expand Up @@ -571,13 +569,14 @@ const KhanAnswerTypes = {
} else if (form === "percent") {
// Otherwise, an error was returned
score.empty = true;
score.message = strings.MISSING_PERCENT_ERROR;
score.message =
ErrorCodes.MISSING_PERCENT_ERROR;
} else {
if (options.simplify !== "enforced") {
score.empty = true;
}
score.message =
strings.NEEDS_TO_BE_SIMPLFIED_ERROR;
ErrorCodes.NEEDS_TO_BE_SIMPLIFIED_ERROR;
}
// The return false below stops the looping of the
// callback since predicate check succeeded.
Expand All @@ -586,7 +585,7 @@ const KhanAnswerTypes = {
}
if (piApprox && predicate(val, Math.abs(val * 0.001))) {
score.empty = true;
score.message = strings.APPROXIMATED_PI_ERROR;
score.message = ErrorCodes.APPROXIMATED_PI_ERROR;
}
}
});
Expand All @@ -604,7 +603,7 @@ const KhanAnswerTypes = {
});
if (!interpretedGuess) {
score.empty = true;
score.message = strings.EXTRA_SYMBOLS_ERROR;
score.message = ErrorCodes.EXTRA_SYMBOLS_ERROR;
return score;
}
}
Expand Down Expand Up @@ -637,14 +636,12 @@ const KhanAnswerTypes = {
createValidatorFunctional: function (
correctAnswer: string,
options: any,
strings: PerseusStrings,
): (arg1: Guess) => Score {
return KhanAnswerTypes.predicate.createValidatorFunctional(
...KhanAnswerTypes.number.convertToPredicate(
correctAnswer,
options,
),
strings,
);
},
},
Expand Down Expand Up @@ -725,7 +722,6 @@ const KhanAnswerTypes = {
createValidatorFunctional: function (
solution: any,
options: any,
strings: PerseusStrings,
): (arg1: Guess) => Score {
return function (guess: Guess): Score {
const score = {
Expand Down Expand Up @@ -787,8 +783,8 @@ const KhanAnswerTypes = {
score.ungraded = true;
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
score.message = result.wrongVariableCase
? strings.WRONG_CASE_ERROR
: strings.WRONG_LETTER_ERROR;
? ErrorCodes.WRONG_CASE_ERROR
: ErrorCodes.WRONG_LETTER_ERROR;
// Don't tell the use they're "almost there" in this case, that may not be true and isn't helpful.
// @ts-expect-error - TS2339 - Property 'suppressAlmostThere' does not exist on type '{ readonly empty: false; readonly correct: false; readonly message: string | null | undefined; readonly guess: any; readonly ungraded: false; }'.
score.suppressAlmostThere = true;
Expand Down Expand Up @@ -821,7 +817,8 @@ const KhanAnswerTypes = {
// @ts-expect-error - TS2540 - Cannot assign to 'ungraded' because it is a read-only property.
score.ungraded = true;
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
score.message = strings.MULTIPLICATION_SIGN_ERROR;
score.message =
ErrorCodes.MULTIPLICATION_SIGN_ERROR;
} else if (resultX.message) {
// TODO(aasmund): I18nize `score.message`
// @ts-expect-error - TS2540 - Cannot assign to 'message' because it is a read-only property.
Expand Down
10 changes: 10 additions & 0 deletions packages/perseus-score/src/version.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// This file is processed by a Rollup plugin (replace) to inject the production
// version number during the release build.
// In dev, you'll never see the version number.

import {addLibraryVersionToPerseusDebug} from "@khanacademy/perseus-core";

const libName = "@khanacademy/perseus-score";
export const libVersion = "__lib_version__";

addLibraryVersionToPerseusDebug(libName, libVersion);
19 changes: 19 additions & 0 deletions packages/perseus-score/tsconfig-build.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
{
"extends": "../tsconfig-shared.json",
"compilerOptions": {
"outDir": "./dist",
"rootDir": "src",
"paths": {
// NOTE(kevinb): We have to repeat this here because TS doesn't do
// intelligent merge of tsconfig.json files when using `extends`.
"@khanacademy/*": [
"../*/src"
]
}
},
"references": [
{"path": "../kas/tsconfig-build.json"},
{"path": "../kmath/tsconfig-build.json"},
{"path": "../perseus-core/tsconfig-build.json"},
]
}
1 change: 1 addition & 0 deletions packages/perseus-score/types
1 change: 1 addition & 0 deletions packages/perseus/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
"@khanacademy/math-input": "^22.1.1",
"@khanacademy/perseus-core": "3.0.5",
"@khanacademy/perseus-linter": "^1.2.11",
"@khanacademy/perseus-score": "^0.0.0",
"@khanacademy/pure-markdown": "^0.3.20",
"@khanacademy/simple-markdown": "^0.13.13",
"@types/classnames": "2.2.0",
Expand Down
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import type {PerseusRenderer} from "../perseus-types";
import type {PerseusRenderer} from "@khanacademy/perseus-core";

export const singleSectionArticle: PerseusRenderer = {
content:
Expand Down
2 changes: 1 addition & 1 deletion packages/perseus/src/__testdata__/graphie.testdata.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import {
ItemExtras,
type PerseusAnswerArea,
type PerseusItem,
} from "../perseus-types";
} from "@khanacademy/perseus-core";

export const itemWithPieChart: PerseusItem = {
answerArea: Object.fromEntries(
Expand Down
4 changes: 2 additions & 2 deletions packages/perseus/src/__testdata__/renderer.testdata.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import type {RenderProps} from "../widgets/radio";
import type {
DropdownWidget,
ImageWidget,
InputNumberWidget,
PerseusRenderer,
} from "../perseus-types";
import type {RenderProps} from "../widgets/radio";
} from "@khanacademy/perseus-core";

export const dropdownWidget: DropdownWidget = {
type: "dropdown",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
type ExpressionWidget,
type RadioWidget,
type NumericInputWidget,
} from "../perseus-types";
} from "@khanacademy/perseus-core";

export const itemWithInput: PerseusItem = {
question: {
Expand Down
2 changes: 1 addition & 1 deletion packages/perseus/src/__tests__/article-renderer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ import ArticleRenderer from "../article-renderer";
import * as Dependencies from "../dependencies";
import {ApiOptions} from "../perseus-api";

import type {PerseusRenderer} from "../perseus-types";
import type {APIOptions} from "../types";
import type {PerseusRenderer} from "@khanacademy/perseus-core";

function KeypadWithContext() {
return (
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ beforeEach(() => {
stub.mockClear();
});

import type {RadioWidget, PerseusWidgetsMap} from "../perseus-types";
import type {RadioWidget, PerseusWidgetsMap} from "@khanacademy/perseus-core";

describe("ExtractPerseusData", () => {
describe("getAnswersFromWidgets", () => {
Expand Down
4 changes: 2 additions & 2 deletions packages/perseus/src/__tests__/mock-asset-loading-widget.tsx
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {ItemExtras} from "@khanacademy/perseus-core";
import * as React from "react";

import AssetContext from "../asset-context";
import {ItemExtras} from "../perseus-types";

import type {PerseusAnswerArea, PerseusItem} from "../perseus-types";
import type {WidgetExports} from "../types";
import type {PerseusAnswerArea, PerseusItem} from "@khanacademy/perseus-core";

export const mockedAssetItem: PerseusItem = {
question: {
Expand Down
2 changes: 1 addition & 1 deletion packages/perseus/src/__tests__/renderer.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,8 @@ import {simpleGroupQuestion} from "../widgets/group/group.testdata";
import InputNumberExport from "../widgets/input-number";
import RadioWidgetExport from "../widgets/radio";

import type {PerseusRenderer, DropdownWidget} from "../perseus-types";
import type {APIOptions} from "../types";
import type {PerseusRenderer, DropdownWidget} from "@khanacademy/perseus-core";
import type {UserEvent} from "@testing-library/user-event";

// NOTE(jeremy): We can't use an automatic mock for the translation linter,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ import MockAssetLoadingWidgetExport, {
} from "./mock-asset-loading-widget";

import type {MockAssetLoadingWidget} from "./mock-asset-loading-widget";
import type {PerseusItem} from "../perseus-types";
import type {APIOptions} from "../types";
import type {KeypadAPI} from "@khanacademy/math-input";
import type {PerseusItem} from "@khanacademy/perseus-core";
import type {PropsFor} from "@khanacademy/wonder-blocks-core";
import type {UserEvent} from "@testing-library/user-event";

Expand Down
Loading

0 comments on commit bc3d955

Please sign in to comment.