From ca31afb359cc00035a4af965f19d20d7919a14a5 Mon Sep 17 00:00:00 2001 From: Matthew Date: Tue, 30 Jul 2024 09:44:34 -0500 Subject: [PATCH] KAS: try to type some things (#1449) * make parser-generator ts * make compare happy with types * add return type for compare * move index to ts * undo that * changeset * respond to Jeremys feedback --- .changeset/shy-scissors-type.md | 5 ++++ packages/kas/package.json | 2 +- packages/kas/src/{compare.js => compare.ts} | 27 +++++++++---------- ...arser-generator.js => parser-generator.ts} | 26 ++++++++---------- packages/kas/src/types.d.ts | 25 +++++++++++++++++ 5 files changed, 54 insertions(+), 31 deletions(-) create mode 100644 .changeset/shy-scissors-type.md rename packages/kas/src/{compare.js => compare.ts} (75%) rename packages/kas/src/{parser-generator.js => parser-generator.ts} (93%) create mode 100644 packages/kas/src/types.d.ts diff --git a/.changeset/shy-scissors-type.md b/.changeset/shy-scissors-type.md new file mode 100644 index 0000000000..3fe0bf611b --- /dev/null +++ b/.changeset/shy-scissors-type.md @@ -0,0 +1,5 @@ +--- +"@khanacademy/kas": patch +--- + +Add some types to the KAS package diff --git a/packages/kas/package.json b/packages/kas/package.json index 078d80a903..728f0e95a2 100644 --- a/packages/kas/package.json +++ b/packages/kas/package.json @@ -22,7 +22,7 @@ "dist" ], "scripts": { - "gen:parsers": "node src/parser-generator.js", + "gen:parsers": "node src/parser-generator.ts", "test": "bash -c 'yarn --silent --cwd \"../..\" test ${@:0} $($([[ ${@: -1} = -* ]] || [[ ${@: -1} = bash ]]) && echo $PWD)'" }, "dependencies": { diff --git a/packages/kas/src/compare.js b/packages/kas/src/compare.ts similarity index 75% rename from packages/kas/src/compare.js rename to packages/kas/src/compare.ts index 0ca59d129c..b1dc865dd7 100644 --- a/packages/kas/src/compare.js +++ b/packages/kas/src/compare.ts @@ -1,12 +1,15 @@ -/* eslint-disable */ -import _ from "underscore"; +import type {CompareOptions, CompareResult, Expression} from "./types"; // Assumes that both expressions have already been parsed // TODO(alex): be able to pass a random() function to compare() -export const compare = function (expr1, expr2, options) { - var defaults = { - form: false, // Check that the two expressions have the same form - simplify: false, // Check that the second expression is simplified +export const compare = function ( + expr1: Expression, + expr2: Expression, + options: CompareOptions, +): CompareResult { + const defaults: CompareOptions = { + form: false, + simplify: false, }; /* Options that could be added in the future: @@ -14,20 +17,14 @@ export const compare = function (expr1, expr2, options) { * like slope * - Allow student to choose their own variable names */ - - if (options !== undefined) { - // eslint-disable-next-line no-undef - options = _.extend(defaults, options); - } else { - options = defaults; - } + options = {...defaults, ...options}; // TODO(CP-1614): Figure out how to make these messages translatable // Variable check - var vars = expr1.sameVars(expr2); + const vars = expr1.sameVars(expr2); if (!vars.equal) { - var message; + let message; if (vars.equalIgnoringCase) { message = "Check your variables; one or more are using " + diff --git a/packages/kas/src/parser-generator.js b/packages/kas/src/parser-generator.ts similarity index 93% rename from packages/kas/src/parser-generator.js rename to packages/kas/src/parser-generator.ts index 2c9e694225..2559c6f45c 100755 --- a/packages/kas/src/parser-generator.js +++ b/packages/kas/src/parser-generator.ts @@ -1,10 +1,6 @@ #!/usr/bin/env node /* eslint-disable @typescript-eslint/no-var-requires */ -/* eslint-disable comma-dangle */ -/* eslint-disable comma-spacing */ /* eslint-disable import/no-commonjs */ -/* eslint-disable max-len */ -/* eslint-disable no-var */ /* eslint-disable prettier/prettier */ const fs = require("fs"); @@ -12,7 +8,7 @@ const path = require("path"); const jison = require("jison"); -var grammar = { +const grammar = { lex: { rules: [ ["\\s+", "/* skip whitespace */"], @@ -204,32 +200,32 @@ var grammar = { }, }; -var prelude = +const prelude = "// This is a @gene" + "rated file\n" + 'import _ from "underscore";\n\n'; -var parser = new jison.Generator(grammar).generate({moduleType: "js"}); +let parser = new jison.Generator(grammar).generate({moduleType: "js"}); // NOTE(jeresig): We need to comment out these two labels as they appear to be // invalid ES5 (they also aren't referenced anywhere so this seems safe). parser = parser.replace(/(_token_stack:)/g, "//$1"); -var postlude = "\n\nexport {parser};\n"; +const postlude = "\n\nexport {parser};\n"; fs.writeFileSync( path.resolve(__dirname, "__genfiles__", "parser.js"), prelude + parser + postlude, ); -var unitPrelude = "// this is a @gene" + "rated file\n\n"; -var unitEpilogue = "\n\nexport const unitParser = parser;\n"; +const unitPrelude = "// this is a @gene" + "rated file\n\n"; +const unitEpilogue = "\n\nexport const unitParser = parser;\n"; -var unitParserInfile = path.resolve(__dirname, "unitvalue.jison"); -var unitParserOutfile = path.resolve( +const unitParserInfile = path.resolve(__dirname, "unitvalue.jison"); +const unitParserOutfile = path.resolve( __dirname, "__genfiles__", "unitparser.js", ); -var unitParserSource = fs.readFileSync(unitParserInfile); -var unitParser = new jison.Generator(unitParserSource.toString()); -var generatedParser = unitParser.generate({moduleType: "js"}); +const unitParserSource = fs.readFileSync(unitParserInfile); +const unitParser = new jison.Generator(unitParserSource.toString()); +let generatedParser = unitParser.generate({moduleType: "js"}); // NOTE(jeresig): We need to comment out these two labels as they appear to be // invalid ES5 (they also aren't referenced anywhere so this seems safe). generatedParser = generatedParser.replace(/(_token_stack:)/g, "//$1"); diff --git a/packages/kas/src/types.d.ts b/packages/kas/src/types.d.ts new file mode 100644 index 0000000000..e2fb3479f1 --- /dev/null +++ b/packages/kas/src/types.d.ts @@ -0,0 +1,25 @@ +export type CompareOptions = { + // Check that the two expressions have the same form + form: boolean; + // Check that the second expression is simplified + simplify: boolean; +}; + +export type CompareResult = { + equal: boolean; + wrongVariableCase?: boolean; + wrongVariableNames?: boolean; + message: string | null; +}; + +export type ExpressionVars = { + equal: boolean; + equalIgnoringCase: boolean; +}; + +export type Expression = { + compare: (expr: Expression) => boolean; + sameVars: (expr: Expression) => ExpressionVars; + sameForm: (expr: Expression) => unknown; + isSimplified: () => boolean; +};