Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Init perseus-score and move answer-types and perseus-types #2086

Merged
merged 10 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Exporting sum here introduces a duplicate function now in that vector.ts has an arraySum() that is exactly the same thing.

Maybe we can de-duplicate in a follow-up PR?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to my "post-move" cleanup ticket: https://khanacademy.atlassian.net/browse/LEMS-2776

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
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For a future PR, I think a small cleanup that'd fit these Khanmath functions into this library would be to move the functions to number.ts or vector.ts (as appropriate). It's a nitpicky thing, but it would make this library more consumable instead of having a grab-bag of functions left in KhanMath.

Probably low priority, but if you feel like it... :)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to my "post-move" cleanup ticket: https://khanacademy.atlassian.net/browse/LEMS-2776

Expand Down
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";
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe this should be export * as DataSchema? It would just be very painful to do without figuring out a way of automating the change because it wouldn't be a simple find/replace.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I like the idea. I think it's something we could tackle as a follow-up.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added to my "post-move" cleanup ticket: https://khanacademy.atlassian.net/browse/LEMS-2776

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 @@
/**

Check warning on line 1 in packages/perseus-score/.babelrc.js

View workflow job for this annotation

GitHub Actions / Lint, Typecheck, Format, and Test (ubuntu-latest, 20.x)

File ignored by default.
* 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,
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since it's now using error placeholders instead of translated strings, we don't need to weave through the strings object.

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice! I was thinking about how this will work out on the frontend and I think your choice of string codes over numeric will be useful. If we ever have a code that's not represented on the frontend, we'll at least have a code that reveals something about what happened on the server.

): (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`.
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is just copy-pasta, I don't know what I'm doing.

"@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.0",
"@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
Loading