@doenet/v06-to-v07 0.7.21-dev.364 → 0.7.21-dev.368

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -42591,7 +42591,7 @@ async function cidFromArrayBuffer(data) {
42591
42591
  await crypto.subtle.digest("SHA-256", new Uint8Array());
42592
42592
  digest = (data2) => crypto.subtle.digest("SHA-256", data2);
42593
42593
  } catch (e22) {
42594
- const sha256 = (await import("./sha256-1m3pbIuR-CcR_uzOg-DFbzNMx_.js").then((n2) => n2.s)).default;
42594
+ const sha256 = (await import("./sha256-1m3pbIuR-C9EeBBiw-C-sYwf5C.js").then((n2) => n2.s)).default;
42595
42595
  digest = (data2) => sha256(data2, {
42596
42596
  asBytes: true
42597
42597
  });
@@ -46357,7 +46357,7 @@ class Indent {
46357
46357
  }
46358
46358
  const chrome$1 = "# Viewer chrome: buttons, panel headers, and other UI the reader interacts\n# with. Rendered on the main thread and selected by `uiLocale`.\n#\n# Message ids are lower-kebab-case Fluent identifiers, optionally with a\n# single `.attribute` suffix (`submit-button`, `answer-status.correct`).\n#\n# This catalog is the source of truth for every other locale: `lint:i18n`\n# rejects a translation that defines a key missing here. Run\n# `npm run codegen -w @doenet/i18n` after editing.\n\n\n## Answer submission — the check-work button and the status it reports.\n\nanswer-checking = Checking...\nanswer-submitting = Submitting...\n\n# Announced to a screen reader while the submission is in flight. Separate\n# from the button's own text, which is abbreviated.\nanswer-checking-status = Checking answer\nanswer-submitting-status = Submitting answer\n\nanswer-correct = Correct\nanswer-incorrect = Incorrect\n\n# Shown instead of a correctness verdict when the activity withholds\n# correctness: the response was recorded, nothing is claimed about it.\nanswer-response-saved = Response Saved\n\n# Partial credit. `-credit` is used when repeated attempts reduce the credit\n# available, `-correct` when they do not, and `-short` on a button too narrow\n# for a word.\nanswer-percent-credit = { $percent }% Credit\nanswer-percent-correct = { $percent }% Correct\nanswer-percent-short = { $percent } %\n\nmax-credit-available = Max credit available: { $percent }%\n\n# Fluent formats `{ $count }` with `Intl.NumberFormat`, so a four-digit\n# attempt count renders as \"1,000\" where the hand-built string said \"1000\".\n# That is the one place English output is not byte-identical to what this\n# replaced, and grouping is the locale-correct rendering, so it stands.\nattempts-remaining =\n { $count ->\n [0] no attempts remaining\n [one] { $count } attempt remaining\n *[other] { $count } attempts remaining\n }\n\n# Appended to an input's accessible name once its response has been graded,\n# so a screen reader reports the verdict along with the field.\nvalidation-correct = (Correct)\nvalidation-incorrect = (Incorrect)\nvalidation-partially-correct = (Partially correct)\n\n# Tooltip on the badge that reports how many responses have been submitted to\n# one answer, shown only to a host that asked for it. `$answerId` is the\n# answer's authored name and is never translated.\nanswer-show-responses =\n { $count ->\n [one] Show { $count } response to { $answerId }\n *[other] Show { $count } responses to { $answerId }\n }\n\n\n## Disclosure panels\n\nfeedback-heading = Feedback\n\n# Follows a disclosure panel's own heading — \"Solution (click to open)\" — and\n# is shared by `<solution>`, `<hint>`, and a collapsible `<section>`. The whole\n# parenthetical is one message: where the word for open or close falls inside\n# it is the translator's business.\ncollapsible-click-to-open = (click to open)\ncollapsible-click-to-close = (click to close)\n\n# Placeholder inside a panel that has been opened before its contents have\n# arrived from the core. Shared by `<solution>` and a collapsible `<section>`.\ncollapsible-initializing = Initializing...\n\n# Tooltip on a footnote marker, naming what activating it will do.\nfootnote-show = Show footnote\nfootnote-hide = Hide footnote\n\n# Tooltip on the ⓘ affordance that reveals an input's description.\ndescription-more-information = more information\n\n\n## Controls\n\nslider-previous = Prev\nslider-next = Next\n\nkeyboard-open = Open Keyboard\nkeyboard-close = Close Keyboard\n\n# Accessible names of a matrix input's size controls, whose visible labels are\n# the symbols `r-` `r+` `c-` `c+`.\nmatrix-remove-row = Remove row\nmatrix-add-row = Add row\nmatrix-remove-column = Remove column\nmatrix-add-column = Add column\n\n# Modes and actions of the subset-of-reals input's control strip. The button\n# that selects all of the reals is the symbol `R`, not a word, and stays in\n# place.\nsubset-add-remove-points = Add/Remove points\nsubset-toggle-points-intervals = Toggle points and intervals\nsubset-move-points = Move Points\nsubset-clear = Clear\n\n# Buttons that edit an orbital diagram: rows hold boxes, boxes hold up to\n# three spin arrows.\norbital-add-row = Add Row\norbital-remove-row = Remove Row\norbital-add-box = Add Box\norbital-remove-box = Remove Box\norbital-add-up-arrow = Add Up Arrow\norbital-add-down-arrow = Add Down Arrow\norbital-remove-arrow = Remove Arrow\n\n# Accessible name of the text field naming one row of an orbital diagram,\n# counting from 1.\norbital-row-label = Label for row { $row }\n\n# Labels the answer column of a pretzel exercise's grid.\npretzel-answer = Answer\n\n# Caption above the table a `<summaryStatistics>` renders. `$column` is the\n# authored name of the data column being summarized and is never translated.\n# The table's own headings (`mean`, `stdev`, `quartile1`, …) are the statistic\n# ids an author references, not prose, and stay in place.\nsummary-statistics-caption = Summary statistics of { $column }\n\n\n## Math input\n\n# Accessible name of the popover that previews the typed expression, and of\n# the rendered expression inside it.\nmath-input-preview-region = math expression preview\nmath-input-preview = Preview\nmath-input-invalid-expression = Invalid expression:\n\n\n## Document status\n\n# Shown while the core is still starting up and nothing can be rendered yet.\nviewer-initializing = Initializing...\n\n\n## Errors\n\n# Prefixes an error message wherever one is shown in place of content: an\n# `<error>` the core reported, the error boundary's fallback, and the\n# placeholder left where a renderer chunk failed to load.\nerror-heading = Error\n\n# Banner above a document that compiled with at least one error in it.\ndocument-contains-errors = This document contains errors!\n\n# Shown in place of the document when a renderer threw and the error boundary\n# caught it.\nsomething-went-wrong = Something went wrong.\n\n# Shown in place of a single renderer whose code chunk never arrived.\nrenderer-load-failed = a renderer failed to load. Please reload the page.\n\n# Shown in place of the document when the core worker could not be started\n# after retries, rather than leaving the pane blank.\ncore-start-failed = The document viewer could not be started. Please reload the page.\n";
46359
46359
  const content = '# Worker-generated content: style descriptions ("thick red line"), boolean\n# words, and other prose the core computes into the document. Selected by\n# `documentLocale`, which follows the content\'s language rather than the\n# reader\'s UI language.\n#\n# Message ids are lower-kebab-case Fluent identifiers, optionally with a\n# single `.attribute` suffix (`color.blue`, `noun.line-segment`).\n\n\n## Style vocabulary\n##\n## The words the style pipeline derives from a component\'s numeric and\n## enumerated style values. A word an author writes directly — `lineColorWord`,\n## `markerStyleWord`, and their siblings — passes through untranslated: the\n## author chose those words, and rewriting them would be a surprise. So does a\n## CSS named color asked for by name ("rebeccapurple"), which\n## `resolveColorWord` deliberately preserves.\n##\n## Every adjective here is handed `$gender`, the grammatical gender of the noun\n## it describes (see `noun-gender`). English has no agreement and ignores it; a\n## language that inflects selects on it.\n\n# The canonical color families a color value resolves to.\ncolor =\n .black = black\n .white = white\n .gray = gray\n .red = red\n .orange = orange\n .yellow = yellow\n .green = green\n .cyan = cyan\n .blue = blue\n .purple = purple\n .pink = pink\n .brown = brown\n\n# Stroke widths. Only the extremes are named — a middling width is described by\n# its color alone.\nline-width =\n .thick = thick\n .thin = thin\n\n# Dash patterns. A solid stroke is described by its color alone.\nline-style =\n .dashed = dashed\n .dotted = dotted\n\n# Patterns a shape\'s interior can be filled with. A solid fill is described by\n# its color alone.\nfill-style =\n .horizontal = horizontal lines\n .vertical = vertical lines\n .diagonal = diagonal lines\n .backdiagonal = reverse diagonal lines\n .dots = dots\n .diamonds = diamonds\n\n# The things being described. The shapes a point can be drawn as ("square",\n# "cross") are nouns too: a point\'s description names its marker shape rather\n# than always saying "point".\nnoun =\n .line = line\n .line-segment = line segment\n .ray = ray\n .vector = vector\n .curve = curve\n .function = function\n .parabola = parabola\n .polyline = polyline\n .polygon = polygon\n .triangle = triangle\n .rectangle = rectangle\n .circle = circle\n .region = region\n .point = point\n .square = square\n .diamond = diamond\n .cross = cross\n .plus = plus\n\n# A regular polygon names its side count, so it is a message of its own rather\n# than one of `noun`\'s attributes.\n#\n# `$part` splits the noun where a language needs it split: `head` is the word\n# the adjectives attach to, `tail` a complement that follows them. English\n# folds the side count into the head and has no tail; Spanish says "polígono\n# regular" and puts "de 5 lados" after the adjectives, so that they stay beside\n# the noun they agree with. `style-with-noun` and `style-filled-with-noun`\n# place the two halves.\n#\n# `$numSides` is a real number, so it is formatted by the locale\'s own rules —\n# a 1000-gon reads "1,000-sided" here and "de 1000 lados" in Spanish. That is\n# the number-formatting policy in the README, and the one place a description\n# is not character-for-character what the pre-catalog code produced.\nnoun-regular-polygon =\n { $part ->\n [tail] { "" }\n *[head] { $numSides }-sided regular polygon\n }\n\n# The grammatical gender of the noun being described, passed to every adjective\n# describing it so that translations can agree. English has no grammatical\n# gender, so every noun answers the same and the answer goes unused.\n#\n# `$noun` is one of `noun`\'s attribute names, `regular-polygon` for the shape\n# `noun-regular-polygon` names, or the head of a phrase the description builds\n# without naming it as a noun: `border`, `fill`, `text`, or `background`. A\n# word this message does not list falls to its default gender — which is also\n# what an author\'s own `markerStyleWord` gets, since the catalog has never seen\n# it.\nnoun-gender = neuter\n\n\n## Style composition\n##\n## `$parts` names which pieces the style actually supplies, so that a\n## translation can order and inflect each combination on its own terms instead\n## of substituting into a fixed English frame. An absent piece is a different\n## branch, never an empty placeable.\n\n# The adjectives describing a stroke: its width, its dash pattern, and its\n# color. Also describes a shape\'s border, where the color is dropped when it\n# matches the fill it surrounds.\nstyle-stroke =\n { $parts ->\n [width-style-color] { $width } { $lineStyle } { $color }\n [width-color] { $width } { $color }\n [style-color] { $lineStyle } { $color }\n [width-style] { $width } { $lineStyle }\n [width] { $width }\n [style] { $lineStyle }\n *[color] { $color }\n }\n\n# A style description followed by what it describes: "thick red line".\n#\n# `$nounTail` is the noun\'s trailing complement, for the nouns whose\n# translation splits around the adjectives (see `noun-regular-polygon`).\n# English has none today, so it only ever selects `noun` for itself — the other\n# variant is still what a partly-translated locale falls back to, and dropping\n# it would drop that locale\'s side count.\nstyle-with-noun =\n { $parts ->\n [noun-tail] { $description } { $noun } { $nounTail }\n *[noun] { $description } { $noun }\n }\n\n# The word marking a shape as filled.\n#\n# A key of its own, looked up by the code and handed to the messages below as\n# `$filled`, rather than literal text inside them: a language that inflects it\n# has to agree it with the shape. Referencing it from those messages would not\n# do — a term reference (`{ -filled }`) gets an empty scope and never sees\n# `$gender`, and a message reference resolves only inside its own bundle, so a\n# locale that translated `style-filled` but not this word would render the\n# reference literally instead of falling back to English.\nstyle-filled-word = filled\n\n# A filled shape, and the pattern its interior is drawn with, if any.\nstyle-filled =\n { $parts ->\n [pattern] { $filled } { $color } with { $pattern }\n *[plain] { $filled } { $color }\n }\n\n# The same, naming the shape: "filled blue circle with diamonds".\n#\n# The `-tail` variants carry the noun\'s trailing complement, as\n# `style-with-noun` does.\nstyle-filled-with-noun =\n { $parts ->\n [pattern] { $filled } { $color } { $noun } with { $pattern }\n [plain-tail] { $filled } { $color } { $noun } { $nounTail }\n [pattern-tail] { $filled } { $color } { $noun } { $nounTail } with { $pattern }\n *[plain] { $filled } { $color } { $noun }\n }\n\n# The border clause appended to a filled shape: "with a thick red border".\n#\n# `$parts` carries two distinctions English cares about: whether a fill pattern\n# was already mentioned, which makes this a further clause ("and") rather than\n# the first ("with"), and whether the surrounding description named the shape,\n# which is where English wants an article.\nstyle-border-clause =\n { $parts ->\n [with-article] with a { $border } border\n [and] and { $border } border\n [and-article] and a { $border } border\n *[with] with { $border } border\n }\n\n# How a shape\'s interior is filled, on its own: "blue diamonds".\nstyle-fill =\n { $parts ->\n [pattern] { $color } { $pattern }\n *[plain] { $color }\n }\n\nstyle-unfilled = unfilled\n\n# How a piece of text is styled: its color, and the background behind it.\nstyle-text =\n { $parts ->\n [background] { $color } with a { $background } background\n *[plain] { $color }\n }\n\n# What `backgroundColor` answers when nothing is drawn behind the text.\nstyle-background-none = none\n';
46360
- const diagnostics = '# Errors and warnings surfaced to the reader or author. Produced by the worker\n# but addressed to whoever is looking at the screen, so these are selected by\n# `uiLocale`, not `documentLocale`.\n#\n# Message ids are lower-kebab-case Fluent identifiers, optionally with a\n# single `.attribute` suffix (`invalid-attribute-value`).\n#\n# Reached by stable diagnostic code rather than by a literal `t("key")` call:\n# `DIAGNOSTIC_CODES` in `src/diagnostics.ts` maps `doenet-w0001` to the id\n# below, and `lint:i18n` treats that registry as the call site. Adding a\n# message here without registering a code for it fails the lint as an orphan.\n#\n# Translators: `through`, `endpoint`, `midpointOffset`, `numDimensions` and the\n# like are DoenetML attribute names. They are part of the language, not prose,\n# and must be left in English exactly as written.\n\n## `<lineSegment>`\n\n# $attributes is a list of attribute names; $attributesCount is its length.\nline-segment-attributes-ignored-with-endpoints =\n { $attributesCount ->\n [one] { $attributes } is ignored when two endpoints are specified\n *[other] { $attributes } are ignored when two endpoints are specified\n }\n\n# $attributes is a list of attribute names; $attributesCount is its length.\nline-segment-attributes-ignored-with-endpoint-and-midpoint =\n { $attributesCount ->\n [one] { $attributes } is ignored when an endpoint and a midpoint are both specified\n *[other] { $attributes } are ignored when an endpoint and a midpoint are both specified\n }\n\nline-segment-midpoint-offset-without-midpoint = midpointOffset has no effect without a midpoint\n\n## `<line>`\n\nline-points-undetermined-dimensions = Line through points of undetermined dimensions.\n\nline-points-too-few-dimensions = Line must be through points of at least two dimensions.\n\n# $variables is a bare enumeration of variable names, not an "and" list.\nline-points-depend-on-variables = Line is through points that depend on variables: { $variables }.\n\nline-equation-invalid-format = Invalid format for equation of line in variables { $variable1 } and { $variable2 }.\n\n## `<ray>`\n\nray-overprescribed-through = Ray is prescribed by through, endpoint, and direction. Ignoring specified through.\n\nray-dimension-mismatch = numDimensions mismatch in ray.\n\n## `<vector>`\n\nvector-overprescribed-head = Vector is prescribed by head, tail, and displacement. Ignoring specified head.\n\nvector-dimension-mismatch = numDimensions mismatch in vector.\n';
46360
+ const diagnostics = '# Errors and warnings surfaced to the reader or author. Produced by the worker\n# but addressed to whoever is looking at the screen, so these are selected by\n# `uiLocale`, not `documentLocale`.\n#\n# Message ids are lower-kebab-case Fluent identifiers, optionally with a\n# single `.attribute` suffix (`invalid-attribute-value`).\n#\n# Reached by stable diagnostic code rather than by a literal `t("key")` call:\n# `DIAGNOSTIC_CODES` in `src/diagnostics.ts` maps `doenet-w0001` to the id\n# below, and `lint:i18n` treats that registry as the call site. Adding a\n# message here without registering a code for it fails the lint as an orphan.\n#\n# Translators: `through`, `endpoint`, `midpointOffset`, `numDimensions` and the\n# like are DoenetML attribute names. They are part of the language, not prose,\n# and must be left in English exactly as written.\n\n## `<lineSegment>`\n\n# $attributes is a list of attribute names; $attributesCount is its length.\nline-segment-attributes-ignored-with-endpoints =\n { $attributesCount ->\n [one] { $attributes } is ignored when two endpoints are specified\n *[other] { $attributes } are ignored when two endpoints are specified\n }\n\n# $attributes is a list of attribute names; $attributesCount is its length.\nline-segment-attributes-ignored-with-endpoint-and-midpoint =\n { $attributesCount ->\n [one] { $attributes } is ignored when an endpoint and a midpoint are both specified\n *[other] { $attributes } are ignored when an endpoint and a midpoint are both specified\n }\n\nline-segment-midpoint-offset-without-midpoint = midpointOffset has no effect without a midpoint\n\n## `<line>`\n\nline-points-undetermined-dimensions = Line through points of undetermined dimensions.\n\nline-points-too-few-dimensions = Line must be through points of at least two dimensions.\n\n# $variables is a bare enumeration of variable names, not an "and" list.\nline-points-depend-on-variables = Line is through points that depend on variables: { $variables }.\n\nline-equation-invalid-format = Invalid format for equation of line in variables { $variable1 } and { $variable2 }.\n\n## `<ray>`\n\nray-overprescribed-through = Ray is prescribed by through, endpoint, and direction. Ignoring specified through.\n\nray-dimension-mismatch = numDimensions mismatch in ray.\n\n## `<vector>`\n\nvector-overprescribed-head = Vector is prescribed by head, tail, and displacement. Ignoring specified head.\n\nvector-dimension-mismatch = numDimensions mismatch in vector.\n\n## Attracting and constraining\n\n# $component is the DoenetML tag of the child that was named, e.g. "polygon".\nattract-to-without-nearest-point = Cannot attract to a `<{ $component }>` as it doesn\'t have a nearestPoint state variable.\n\nconstrain-to-without-nearest-point = Cannot constrain to a `<{ $component }>` as it doesn\'t have a nearestPoint state variable.\n\nconstrain-to-interior-without-nearest-point = Cannot constrain to interior of a `<{ $component }>` as it doesn\'t have a nearestPoint state variable.\n\n## `<choiceInput>`\n\n# Translators: `labelPosition` is an attribute name and stays in English.\nchoice-input-label-position-ignored = labelPosition is ignored for non-inline choiceInput\n\n## Ordering children by index\n##\n## These name the component in prose rather than as a tag, matching how the\n## messages have always read. The component names stay in English; the nouns\n## around them are prose and should be translated.\n\nchoice-input-indices-count-mismatch = Ignoring indices specified for choiceInput as number of indices doesn\'t match number of choice children.\n\npretzel-indices-count-mismatch = Ignoring indices specified for problem as number of indices doesn\'t match number of problem children.\n\nshuffle-indices-count-mismatch = Ignoring indices specified for shuffle as number of indices doesn\'t match number of components.\n\n# $component is `choiceInput`, `pretzel` or `shuffle` — a DoenetML component\n# name, so it stays in English.\nindices-ignored-out-of-range = Ignoring indices specified for { $component } as some indices out of range.\n\npretzel-indices-repeated = Ignoring indices specified for pretzel as some indices are repeated.\n\npretzel-circuit-first-index = Ignoring indices specified for pretzel in circuit mode as the first index must be 1.\n\n## `<shuffle>` and `<sort>`\n\n# $component is `shuffle` or `sort`. These two components accept the same\n# children and fail the same ways, so they share their messages.\nstring-children-need-type = For `<{ $component }>` to work with string children, a `type` attribute must be specified.\n\n# $type is what the author wrote; math, text, number and boolean are attribute\n# values and stay in English.\ninvalid-type-defaulting-to-math = Invalid type { $type } for { $component } component. Must be one of math, text, number, or boolean. Defaulting to math.\n\n# $value is the string child that could not be used.\nstring-not-valid-component-to-arrange = String "{ $value }" is not a valid component to { $component }. Ignoring.\n\n## Types and variables\n\ninvalid-type-defaulting-to-number = Invalid type { $type }, setting type to number.\n\ninvalid-variable-value = Invalid value of a variable: `{ $value }`\n\n## Variants\n\n# $index is what the author wrote, reproduced verbatim rather than as a number:\n# it reached this message precisely because it was not one.\nvariant-index-must-be-number = Variant index { $index } must be a number\n\nvariant-index-must-be-integer = Variant index { $index } must be an integer\n\n## `<sideBySide>`\n\n# $component is `sideBySide` or `sbsGroup`.\nside-by-side-absolute-widths = `<{ $component }>` is not implemented for absolute measurements. Setting widths to relative.\n\nside-by-side-absolute-margins = `<{ $component }>` is not implemented for absolute measurements. Setting margins to relative.\n\nside-by-side-no-block-child = Invalid `<{ $component }>`: it must have at least one block child.\n\n## `<label>`\n\n# Translators: `for` is an attribute name and stays in English.\nlabel-for-ignored-on-graphical = The `for` attribute on graphical `<label>` is ignored.\n\nlabel-for-must-resolve-to-one = The `for` attribute on `<label>` must resolve to exactly one component.\n\nlabel-for-unresolved = The `for` attribute on `<label>` could not be resolved to a component.\n\nlabel-for-answer-with-authored-inputs = The `for` attribute on `<label>` references an `<answer>` with explicitly authored inputs; reference the input directly.\n\nlabel-for-answer-without-input = The `for` attribute on `<label>` references an `<answer>` without an input to label.\n\nlabel-for-must-reference-input-or-answer = The `for` attribute on `<label>` must reference an input or an answer.\n\n## Accessibility\n\n# $component is a DoenetML tag, e.g. "graph" or "image".\naccessibility-short-description-or-decorative = For accessibility, `<{ $component }>` must either have a short description or be specified as decorative.\n\naccessibility-video-short-description = For accessibility, `<video>` must have a short description.\n\naccessibility-input-short-description-or-label = For accessibility, `<{ $component }>` must have a short description or a label.\n\n# The companion to the message above, for the input an `<answer>` creates on the\n# author\'s behalf. Two messages rather than one with the subject passed in: the\n# subject is a phrase here, not a name, and a phrase handed over as an argument\n# would never reach a translator.\naccessibility-answer-input-short-description-or-label = For accessibility, an `<answer>` creating an input must have a short description or a label.\n\naccessibility-short-description-contains-math = Short descriptions should not contain math components such as `<{ $component }>`. Spell out any math with words.\n\n# $colorName is an attribute name and stays in English. $ratio and $threshold\n# are contrast ratios; $mode says which theme the shortfall was measured in,\n# and is `dark` or `light`.\naccessibility-section-title-insufficient-contrast =\n { $mode ->\n [dark] { $colorName } has insufficient contrast for the section heading text (dark mode) ({ NUMBER($ratio, minimumFractionDigits: 2, maximumFractionDigits: 2) }:1; requires at least { $threshold }:1).\n *[other] { $colorName } has insufficient contrast for the section heading text ({ NUMBER($ratio, minimumFractionDigits: 2, maximumFractionDigits: 2) }:1; requires at least { $threshold }:1).\n }\n\n## `<circle>`\n\n# $count is the number of through points.\ncircle-through-points-non-numerical = Haven\'t implemented `<circle>` through { $count } points in case where the points don\'t have numerical values.\n\ncircle-too-many-through-points = Cannot calculate circle through more than 3 points.\n\ncircle-overprescribed-radius-center-points = Cannot calculate circle with specified radius, center and through points.\n\ncircle-center-with-multiple-points = Cannot calculate circle with specified center through more than 1 point.\n\n# $distance and $radius arrive as strings, not numbers: $radius is the author\'s\n# own value echoed back for diagnosis, and formatting it as a quantity would\n# round a radius of 0.0001 away to 0.\ncircle-radius-too-small = Cannot calculate circle: given that the distance between the two points is { $distance }, the specified radius { $radius } is too small.\n\ncircle-radius-with-many-points = Cannot create circle through more than two points with a specified radius.\n\ncircle-invalid-center-or-through-points = Invalid center or through points of circle.\n\ncircle-radius-center-with-multiple-points = Cannot calculate radius of circle with specified center through more than 1 point.\n\ncircle-change-radius-non-numerical = Cannot change radius of circle with non-numerical through points\n\ncircle-radius-with-points-non-numerical = Cannot create circle through more than one point with specified radius when don\'t have numerical values.\n\ncircle-change-center-non-numerical = Haven\'t implemented changing center of circle through points with non numerical values.\n\n## `<function>`\n\n# Two independent counts in one sentence, so the variants multiply out. A\n# select\'s variants each need their own line, so the inner one spans lines too;\n# that is safe because newlines inside a placeable never reach the rendered\n# value. Only text continuing onto a further line would.\nfunction-domain-insufficient-dimensions =\n { $intervals ->\n [one] Insufficient dimensions for domain for function. Domain has { $intervals } interval but the function has { $inputs ->\n [one] { $inputs } input\n *[other] { $inputs } inputs\n }.\n *[other] Insufficient dimensions for domain for function. Domain has { $intervals } intervals but the function has { $inputs ->\n [one] { $inputs } input\n *[other] { $inputs } inputs\n }.\n }\n\nfunction-domain-invalid-format = Invalid format for domain for function.\n\n# $type is what was being read off the point. It selects the wording rather\n# than being substituted into it: "maximum", "slope" and the rest are English\n# nouns, and a noun handed over as an argument would never reach a translator.\n# The catch-all reproduces the pre-catalog behavior for a value not listed here.\nfunction-ignoring-non-numerical =\n { $type ->\n [maximum] Ignoring non-numerical maximum of function.\n [minimum] Ignoring non-numerical minimum of function.\n [extremum] Ignoring non-numerical extremum of function.\n [point] Ignoring non-numerical point of function.\n [slope] Ignoring non-numerical slope of function.\n *[other] Ignoring non-numerical { $type } of function.\n }\n\nfunction-ignoring-empty =\n { $type ->\n [maximum] Ignoring empty maximum of function.\n [minimum] Ignoring empty minimum of function.\n [extremum] Ignoring empty extremum of function.\n [point] Ignoring empty point of function.\n *[other] Ignoring empty { $type } of function.\n }\n\nfunction-points-too-close = Function contains two points with locations too close together. Can\'t define function.\n\nfunction-iterates-input-output-mismatch =\n { $inputs ->\n [one] Function iterates are possible only if the number of inputs of the function is equal to the number of outputs. This function has { $inputs } input and { $outputs ->\n [one] { $outputs } output\n *[other] { $outputs } outputs\n }.\n *[other] Function iterates are possible only if the number of inputs of the function is equal to the number of outputs. This function has { $inputs } inputs and { $outputs ->\n [one] { $outputs } output\n *[other] { $outputs } outputs\n }.\n }\n\n## `<sequence>`\n\nsequence-invalid-length = Invalid length of sequence. Must be a non-negative integer.\n\n# $type is a sequence type: number, letters, or math.\nsequence-invalid-step = Invalid step of sequence. Must be a number for sequence of type { $type }.\n\n# $attribute is `from` or `to` — an attribute name, so it stays in English.\nsequence-invalid-endpoint-number = Invalid "{ $attribute }" of number sequence. Must be a number.\n\nsequence-invalid-endpoint-letters = Invalid "{ $attribute }" of letters sequence. Must be a letter combination.\n\nsequence-invalid-endpoint = Invalid "{ $attribute }" of sequence.\n\nselect-from-sequence-coprime-not-numbers = coprime ignored since not selecting numbers\n\nselect-from-sequence-coprime-with-exclude-combinations = coprime ignored since excludeCombinations specified\n\n## Resolving a `target`\n##\n## Raised by the components that take a `target` attribute. They resolve it\n## through the same code and fail the same two ways, so they share these two\n## messages rather than spelling each one out per component: $source is the tag\n## of the component that raised it, part of the DoenetML language, so it stays\n## in English.\n\ntarget-not-found = Invalid target for `<{ $source }>`: cannot find target.\n\n# $property is the state variable that was looked for; $component is the tag it\n# was looked for on.\ntarget-state-variable-not-found = Invalid target for `<{ $source }>`: cannot find a state variable named "{ $property }" on a `<{ $component }>`.\n\n## `<odeSystem>`\n\node-system-variables-match-independent = Variables of `<odeSystem>` must be different than independent variable.\n\node-system-duplicate-variable-names = Can\'t define ODE RHS functions with duplicate dependent variable names.\n\node-system-rhs-function-error = Cannot define ODE RHS function. Error creating mathjs function.\n\n## `<angle>`, `<parabola>`, and `<intersection>`\n\n# $count is how many line children were found.\nangle-too-many-lines = Cannot define an angle between { $count } lines\n\nangle-invalid-through-point = Invalid point in through of `<angle>`\n\nparabola-vertex-too-many-points = Haven\'t implemented parabola with vertex through more than 1 point.\n\nparabola-too-many-points = Haven\'t implemented parabola through more than 3 points.\n\nintersection-too-many-items = Haven\'t implemented intersection for more than two items\n\n## Other math components\n\nionic-compound-not-two-ions = Have not implemented ionic compound for anything other than two ions.\n\nionic-compound-needs-cation-and-anion = Ionic compound implemented only for one cation and one anion.\n\n# $equation is the equation as the author wrote it.\nsolve-equations-cannot-evaluate = Cannot solve equation as could not evaluate equation: { $equation }\n\n# Translators: `operandNumber` is an attribute name and stays in English.\nmath-operators-operand-number-required = Must specify a operandNumber when extracting a math operand.\n\neigen-decomposition-failed = Could not calculate eigenvalues of matrix\n';
46361
46361
  const editor = "# Editor and language-server surfaces: formatter labels, completion detail\n# text, hover help. Selected by `uiLocale`.\n#\n# Intentionally empty in i18n Phase 0 (#1515). A later phase moves the editor\n# strings into this file; note that the LSP ships bundled with its DoenetML\n# version, so these catalogs are version-correct rather than always-latest.\n#\n# Message ids are lower-kebab-case Fluent identifiers, optionally with a\n# single `.attribute` suffix (`format-document`).\n";
46362
46362
  const CATALOG_NAMESPACES = [
46363
46363
  "chrome",
@@ -46717,7 +46717,7 @@ function normalizeLocaleTag(tag2) {
46717
46717
  }
46718
46718
  const esChrome = "# Spanish viewer chrome. Translated from `locales/en/chrome.ftl`, which is the\n# source of truth: `lint:i18n` rejects a key that does not exist there, and\n# reports a key that exists there but not here as missing coverage.\n#\n# Message ids are never translated — only the text to the right of `=`.\n#\n# Register: impersonal throughout — infinitives and bare nouns, never a `tú`\n# or `usted` verb form. The viewer does not know how formally a deployment\n# addresses its readers, and an impersonal label is correct for both.\n\n\n## Answer submission\n\nanswer-checking = Comprobando...\nanswer-submitting = Enviando...\n\nanswer-checking-status = Comprobando la respuesta\nanswer-submitting-status = Enviando la respuesta\n\nanswer-correct = Correcto\nanswer-incorrect = Incorrecto\n\nanswer-response-saved = Respuesta guardada\n\n# Spanish typographic convention puts a space before the percent sign.\nanswer-percent-credit = { $percent } % de crédito\nanswer-percent-correct = { $percent } % correcto\nanswer-percent-short = { $percent } %\n\nmax-credit-available = Crédito máximo disponible: { $percent } %\n\nattempts-remaining =\n { $count ->\n [0] no quedan intentos\n [one] queda { $count } intento\n *[other] quedan { $count } intentos\n }\n\nvalidation-correct = (Correcto)\nvalidation-incorrect = (Incorrecto)\nvalidation-partially-correct = (Parcialmente correcto)\n\n# `Mostrar` is the infinitive, per the register note above.\nanswer-show-responses =\n { $count ->\n [one] Mostrar { $count } respuesta a { $answerId }\n *[other] Mostrar { $count } respuestas a { $answerId }\n }\n\n\n## Disclosure panels\n\nfeedback-heading = Comentarios\n\ncollapsible-click-to-open = (clic para abrir)\ncollapsible-click-to-close = (clic para cerrar)\ncollapsible-initializing = Inicializando...\n\nfootnote-show = Mostrar la nota al pie\nfootnote-hide = Ocultar la nota al pie\n\ndescription-more-information = más información\n\n\n## Controls\n\nslider-previous = Anterior\nslider-next = Siguiente\n\nkeyboard-open = Abrir el teclado\nkeyboard-close = Cerrar el teclado\n\nmatrix-remove-row = Eliminar fila\nmatrix-add-row = Añadir fila\nmatrix-remove-column = Eliminar columna\nmatrix-add-column = Añadir columna\n\nsubset-add-remove-points = Añadir/Eliminar puntos\nsubset-toggle-points-intervals = Alternar puntos e intervalos\nsubset-move-points = Mover puntos\nsubset-clear = Borrar\n\norbital-add-row = Añadir fila\norbital-remove-row = Eliminar fila\norbital-add-box = Añadir casilla\norbital-remove-box = Eliminar casilla\norbital-add-up-arrow = Añadir flecha hacia arriba\norbital-add-down-arrow = Añadir flecha hacia abajo\norbital-remove-arrow = Eliminar flecha\n\norbital-row-label = Etiqueta de la fila { $row }\n\npretzel-answer = Respuesta\n\nsummary-statistics-caption = Resumen estadístico de { $column }\n\n\n## Math input\n\nmath-input-preview-region = vista previa de la expresión matemática\nmath-input-preview = Vista previa\nmath-input-invalid-expression = Expresión no válida:\n\n\n## Document status\n\nviewer-initializing = Inicializando...\n\n\n## Errors\n\nerror-heading = Error\n\ndocument-contains-errors = ¡Este documento contiene errores!\n\nsomething-went-wrong = Algo salió mal.\n\n# Follows `error-heading` and a colon, so it begins in lower case, as in\n# English. The instruction is an infinitive, per the register note above.\nrenderer-load-failed = no se pudo cargar un componente. Recargar la página.\n\ncore-start-failed = No se pudo iniciar el visor del documento. Recargar la página.\n";
46719
46719
  const esContent = "# Spanish content catalog: the prose the core computes into the document.\n# Selected by `documentLocale` — the language the activity was written in.\n#\n# Spanish inflects. Adjectives follow their noun and agree with it in gender,\n# so every adjective below selects on `$gender`, the gender of the noun it\n# describes, and the composition messages put the noun first. Neither is\n# expressible by substituting into the English word order, which is why the\n# catalog controls the order and not the code.\n\n\n## Vocabulario de estilos\n\ncolor =\n .black =\n { $gender ->\n [f] negra\n *[m] negro\n }\n .white =\n { $gender ->\n [f] blanca\n *[m] blanco\n }\n .gray = gris\n .red =\n { $gender ->\n [f] roja\n *[m] rojo\n }\n .orange = naranja\n .yellow =\n { $gender ->\n [f] amarilla\n *[m] amarillo\n }\n .green = verde\n .cyan = cian\n .blue = azul\n .purple =\n { $gender ->\n [f] morada\n *[m] morado\n }\n .pink = rosa\n .brown = marrón\n\nline-width =\n .thick =\n { $gender ->\n [f] gruesa\n *[m] grueso\n }\n .thin =\n { $gender ->\n [f] delgada\n *[m] delgado\n }\n\nline-style =\n .dashed =\n { $gender ->\n [f] discontinua\n *[m] discontinuo\n }\n .dotted =\n { $gender ->\n [f] punteada\n *[m] punteado\n }\n\n# Sintagmas nominales: van detrás de «con» y no concuerdan con nada.\nfill-style =\n .horizontal = líneas horizontales\n .vertical = líneas verticales\n .diagonal = líneas diagonales\n .backdiagonal = líneas diagonales inversas\n .dots = puntos\n .diamonds = rombos\n\nnoun =\n .line = línea\n .line-segment = segmento\n .ray = semirrecta\n .vector = vector\n .curve = curva\n .function = función\n .parabola = parábola\n .polyline = polilínea\n .polygon = polígono\n .triangle = triángulo\n .rectangle = rectángulo\n .circle = círculo\n .region = región\n .point = punto\n .square = cuadrado\n .diamond = rombo\n .cross = cruz\n .plus = signo más\n\n# El nombre se parte: «polígono regular» lleva los adjetivos y «de 5 lados»\n# cierra el sintagma detrás de ellos. Si el complemento fuera delante, los\n# adjetivos quedarían separados del nombre con el que concuerdan («polígono\n# regular de 5 lados grueso rojo»).\nnoun-regular-polygon =\n { $part ->\n [tail] de { $numSides } lados\n *[head] polígono regular\n }\n\n# Además de los nombres de arriba, `$noun` puede ser «regular-polygon» (el\n# nombre que compone `noun-regular-polygon`) o el núcleo de un sintagma que no\n# se nombra en la descripción: «border», «fill», «text» y «background». Todos\n# ellos son masculinos en español —polígono, borde, relleno, texto, fondo—, así\n# que caen en el caso por defecto.\nnoun-gender =\n { $noun ->\n [line] f\n [ray] f\n [curve] f\n [function] f\n [parabola] f\n [polyline] f\n [region] f\n [cross] f\n *[other] m\n }\n\n\n## Composición de estilos\n\nstyle-stroke =\n { $parts ->\n [width-style-color] { $lineStyle } { $width } { $color }\n [width-color] { $width } { $color }\n [style-color] { $lineStyle } { $color }\n [width-style] { $lineStyle } { $width }\n [width] { $width }\n [style] { $lineStyle }\n *[color] { $color }\n }\n\n# El nombre va delante y los adjetivos detrás: «línea discontinua gruesa roja».\n# El complemento del nombre, si lo hay, cierra el sintagma: «polígono regular\n# grueso rojo de 5 lados».\nstyle-with-noun =\n { $parts ->\n [noun-tail] { $noun } { $description } { $nounTail }\n *[noun] { $noun } { $description }\n }\n\nstyle-filled-word =\n { $gender ->\n [f] rellena\n *[m] relleno\n }\n\nstyle-filled =\n { $parts ->\n [pattern] { $color } { $filled } con { $pattern }\n *[plain] { $color } { $filled }\n }\n\n# Aquí el complemento va pegado al nombre, y no al final como en\n# `style-with-noun`: «relleno de …» se lee como «lleno de …», así que «relleno\n# de 5 lados» diría otra cosa. «Polígono regular de 5 lados azul relleno».\nstyle-filled-with-noun =\n { $parts ->\n [pattern] { $noun } { $color } { $filled } con { $pattern }\n [plain-tail] { $noun } { $nounTail } { $color } { $filled }\n [pattern-tail] { $noun } { $nounTail } { $color } { $filled } con { $pattern }\n *[plain] { $noun } { $color } { $filled }\n }\n\n# «borde» es masculino, así que los adjetivos del borde concuerdan con él y no\n# con la figura que rodea.\nstyle-border-clause =\n { $parts ->\n [with-article] con un borde { $border }\n [and] y borde { $border }\n [and-article] y un borde { $border }\n *[with] con borde { $border }\n }\n\n# «de color» evita tener que concordar el color con un patrón en plural.\nstyle-fill =\n { $parts ->\n [pattern] { $pattern } de color { $color }\n *[plain] { $color }\n }\n\nstyle-unfilled = sin relleno\n\nstyle-text =\n { $parts ->\n [background] { $color } con un fondo { $background }\n *[plain] { $color }\n }\n\nstyle-background-none = ninguno\n";
46720
- const esDiagnostics = "# Advertencias y errores mostrados a quien lee o escribe el documento.\n# Seleccionados por `uiLocale`.\n#\n# Los nombres de atributos y componentes de DoenetML (`through`, `endpoint`,\n# `numDimensions`, …) forman parte del lenguaje y se dejan en inglés.\n\n## `<lineSegment>`\n\nline-segment-attributes-ignored-with-endpoints =\n { $attributesCount ->\n [one] { $attributes } se ignora cuando se especifican los dos extremos\n *[other] { $attributes } se ignoran cuando se especifican los dos extremos\n }\n\nline-segment-attributes-ignored-with-endpoint-and-midpoint =\n { $attributesCount ->\n [one] { $attributes } se ignora cuando se especifican un extremo y el punto medio\n *[other] { $attributes } se ignoran cuando se especifican un extremo y el punto medio\n }\n\nline-segment-midpoint-offset-without-midpoint = midpointOffset no tiene efecto sin un punto medio\n\n## `<line>`\n\n# «Recta», no «línea», aunque `noun.line` en content.ftl diga «línea»: no es\n# una incoherencia, sino la diferencia entre describir el trazo dibujado («una\n# línea azul gruesa») y hablar del objeto geométrico, que en matemáticas es\n# una recta —de ahí «la ecuación de la recta».\n\nline-points-undetermined-dimensions = La recta pasa por puntos de dimensiones indeterminadas.\n\nline-points-too-few-dimensions = La recta debe pasar por puntos de al menos dos dimensiones.\n\nline-points-depend-on-variables = La recta pasa por puntos que dependen de las variables: { $variables }.\n\n# Enumeradas con coma en vez de «y»: las variables de <line> son `x` e `y` por\n# omisión, y «en las variables x y y» sería a la vez incorrecto (ante el sonido\n# /i/ la conjunción es «e») e ilegible. La coma es correcta sea cual sea el\n# nombre de la variable, que aquí no se conoce de antemano.\nline-equation-invalid-format = Formato no válido para la ecuación de la recta en las variables { $variable1 }, { $variable2 }.\n\n## `<ray>`\n\nray-overprescribed-through = La semirrecta está determinada por through, endpoint y direction. Se ignora el through especificado.\n\nray-dimension-mismatch = Discrepancia de numDimensions en la semirrecta.\n\n## `<vector>`\n\nvector-overprescribed-head = El vector está determinado por head, tail y displacement. Se ignora el head especificado.\n\nvector-dimension-mismatch = Discrepancia de numDimensions en el vector.\n";
46720
+ const esDiagnostics = '# Advertencias y errores mostrados a quien lee o escribe el documento.\n# Seleccionados por `uiLocale`.\n#\n# Los nombres de atributos y componentes de DoenetML (`through`, `endpoint`,\n# `numDimensions`, …) forman parte del lenguaje y se dejan en inglés.\n\n## `<lineSegment>`\n\nline-segment-attributes-ignored-with-endpoints =\n { $attributesCount ->\n [one] { $attributes } se ignora cuando se especifican los dos extremos\n *[other] { $attributes } se ignoran cuando se especifican los dos extremos\n }\n\nline-segment-attributes-ignored-with-endpoint-and-midpoint =\n { $attributesCount ->\n [one] { $attributes } se ignora cuando se especifican un extremo y el punto medio\n *[other] { $attributes } se ignoran cuando se especifican un extremo y el punto medio\n }\n\nline-segment-midpoint-offset-without-midpoint = midpointOffset no tiene efecto sin un punto medio\n\n## `<line>`\n\n# «Recta», no «línea», aunque `noun.line` en content.ftl diga «línea»: no es\n# una incoherencia, sino la diferencia entre describir el trazo dibujado («una\n# línea azul gruesa») y hablar del objeto geométrico, que en matemáticas es\n# una recta —de ahí «la ecuación de la recta».\n\nline-points-undetermined-dimensions = La recta pasa por puntos de dimensiones indeterminadas.\n\nline-points-too-few-dimensions = La recta debe pasar por puntos de al menos dos dimensiones.\n\nline-points-depend-on-variables = La recta pasa por puntos que dependen de las variables: { $variables }.\n\n# Enumeradas con coma en vez de «y»: las variables de <line> son `x` e `y` por\n# omisión, y «en las variables x y y» sería a la vez incorrecto (ante el sonido\n# /i/ la conjunción es «e») e ilegible. La coma es correcta sea cual sea el\n# nombre de la variable, que aquí no se conoce de antemano.\nline-equation-invalid-format = Formato no válido para la ecuación de la recta en las variables { $variable1 }, { $variable2 }.\n\n## `<ray>`\n\nray-overprescribed-through = La semirrecta está determinada por through, endpoint y direction. Se ignora el through especificado.\n\nray-dimension-mismatch = Discrepancia de numDimensions en la semirrecta.\n\n## `<vector>`\n\nvector-overprescribed-head = El vector está determinado por head, tail y displacement. Se ignora el head especificado.\n\nvector-dimension-mismatch = Discrepancia de numDimensions en el vector.\n\n## Atraer y restringir\n\nattract-to-without-nearest-point = No se puede atraer a un `<{ $component }>` porque no tiene la variable de estado nearestPoint.\n\nconstrain-to-without-nearest-point = No se puede restringir a un `<{ $component }>` porque no tiene la variable de estado nearestPoint.\n\nconstrain-to-interior-without-nearest-point = No se puede restringir al interior de un `<{ $component }>` porque no tiene la variable de estado nearestPoint.\n\n## `<choiceInput>`\n\nchoice-input-label-position-ignored = labelPosition se ignora en un choiceInput que no es inline\n\n## Ordenar hijos por índice\n\nchoice-input-indices-count-mismatch = Se ignoran los índices especificados para choiceInput porque su cantidad no coincide con la cantidad de hijos choice.\n\npretzel-indices-count-mismatch = Se ignoran los índices especificados para problem porque su cantidad no coincide con la cantidad de hijos problem.\n\nshuffle-indices-count-mismatch = Se ignoran los índices especificados para shuffle porque su cantidad no coincide con la cantidad de componentes.\n\nindices-ignored-out-of-range = Se ignoran los índices especificados para { $component } porque algunos están fuera de rango.\n\npretzel-indices-repeated = Se ignoran los índices especificados para pretzel porque algunos están repetidos.\n\npretzel-circuit-first-index = Se ignoran los índices especificados para pretzel en modo circuit porque el primer índice debe ser 1.\n\n## `<shuffle>` y `<sort>`\n\nstring-children-need-type = Para que `<{ $component }>` funcione con hijos de texto, se debe especificar el atributo `type`.\n\ninvalid-type-defaulting-to-math = Tipo no válido { $type } para el componente { $component }. Debe ser math, text, number o boolean. Se usa math.\n\nstring-not-valid-component-to-arrange = La cadena "{ $value }" no es un componente válido para { $component }. Se ignora.\n\n## Tipos y variables\n\ninvalid-type-defaulting-to-number = Tipo no válido { $type }, se establece el tipo en number.\n\ninvalid-variable-value = Valor no válido de una variable: `{ $value }`\n\n## Variantes\n\nvariant-index-must-be-number = El índice de variante { $index } debe ser un número\n\nvariant-index-must-be-integer = El índice de variante { $index } debe ser un número entero\n\n## `<sideBySide>`\n\nside-by-side-absolute-widths = `<{ $component }>` no está implementado para medidas absolutas. Los anchos se establecen como relativos.\n\nside-by-side-absolute-margins = `<{ $component }>` no está implementado para medidas absolutas. Los márgenes se establecen como relativos.\n\nside-by-side-no-block-child = `<{ $component }>` no es válido: debe tener al menos un hijo de bloque.\n\n## `<label>`\n\nlabel-for-ignored-on-graphical = Se ignora el atributo `for` en un `<label>` gráfico.\n\nlabel-for-must-resolve-to-one = El atributo `for` de `<label>` debe corresponder exactamente a un componente.\n\nlabel-for-unresolved = No se pudo resolver el atributo `for` de `<label>` a un componente.\n\nlabel-for-answer-with-authored-inputs = El atributo `for` de `<label>` hace referencia a un `<answer>` con entradas escritas explícitamente; haz referencia a la entrada directamente.\n\nlabel-for-answer-without-input = El atributo `for` de `<label>` hace referencia a un `<answer>` que no tiene ninguna entrada que etiquetar.\n\nlabel-for-must-reference-input-or-answer = El atributo `for` de `<label>` debe hacer referencia a una entrada o a un `<answer>`.\n\n## Accesibilidad\n\naccessibility-short-description-or-decorative = Por accesibilidad, `<{ $component }>` debe tener una descripción breve o estar marcado como decorativo.\n\naccessibility-video-short-description = Por accesibilidad, `<video>` debe tener una descripción breve.\n\naccessibility-input-short-description-or-label = Por accesibilidad, `<{ $component }>` debe tener una descripción breve o una etiqueta.\n\naccessibility-answer-input-short-description-or-label = Por accesibilidad, la entrada creada por un `<answer>` debe tener una descripción breve o una etiqueta.\n\naccessibility-short-description-contains-math = Las descripciones breves no deben contener componentes matemáticos como `<{ $component }>`. Expresa las matemáticas con palabras.\n\naccessibility-section-title-insufficient-contrast =\n { $mode ->\n [dark] { $colorName } no tiene suficiente contraste con el texto del encabezado de sección (modo oscuro) ({ NUMBER($ratio, minimumFractionDigits: 2, maximumFractionDigits: 2) }:1; se requiere al menos { $threshold }:1).\n *[other] { $colorName } no tiene suficiente contraste con el texto del encabezado de sección ({ NUMBER($ratio, minimumFractionDigits: 2, maximumFractionDigits: 2) }:1; se requiere al menos { $threshold }:1).\n }\n\n## `<circle>`\n\ncircle-through-points-non-numerical = No está implementado un `<circle>` que pase por { $count } puntos cuando los puntos no tienen valores numéricos.\n\ncircle-too-many-through-points = No se puede calcular una circunferencia que pase por más de 3 puntos.\n\ncircle-overprescribed-radius-center-points = No se puede calcular una circunferencia con radio, centro y puntos de paso especificados a la vez.\n\ncircle-center-with-multiple-points = No se puede calcular una circunferencia con centro especificado que pase por más de 1 punto.\n\ncircle-radius-too-small = No se puede calcular la circunferencia: dado que la distancia entre los dos puntos es { $distance }, el radio especificado { $radius } es demasiado pequeño.\n\ncircle-radius-with-many-points = No se puede crear una circunferencia que pase por más de dos puntos con un radio especificado.\n\ncircle-invalid-center-or-through-points = El centro o los puntos de paso de la circunferencia no son válidos.\n\ncircle-radius-center-with-multiple-points = No se puede calcular el radio de una circunferencia con centro especificado que pase por más de 1 punto.\n\ncircle-change-radius-non-numerical = No se puede cambiar el radio de una circunferencia con puntos de paso no numéricos\n\ncircle-radius-with-points-non-numerical = No se puede crear una circunferencia que pase por más de un punto con un radio especificado cuando no hay valores numéricos.\n\ncircle-change-center-non-numerical = No está implementado cambiar el centro de una circunferencia que pasa por puntos con valores no numéricos.\n\n## `<function>`\n\nfunction-domain-insufficient-dimensions =\n { $intervals ->\n [one] Dimensiones insuficientes para el dominio de la función. El dominio tiene { $intervals } intervalo pero la función tiene { $inputs ->\n [one] { $inputs } entrada\n *[other] { $inputs } entradas\n }.\n *[other] Dimensiones insuficientes para el dominio de la función. El dominio tiene { $intervals } intervalos pero la función tiene { $inputs ->\n [one] { $inputs } entrada\n *[other] { $inputs } entradas\n }.\n }\n\nfunction-domain-invalid-format = Formato no válido para el dominio de la función.\n\nfunction-ignoring-non-numerical =\n { $type ->\n [maximum] Se ignora el máximo no numérico de la función.\n [minimum] Se ignora el mínimo no numérico de la función.\n [extremum] Se ignora el extremo no numérico de la función.\n [point] Se ignora el punto no numérico de la función.\n [slope] Se ignora la pendiente no numérica de la función.\n *[other] Se ignora { $type } no numérico de la función.\n }\n\nfunction-ignoring-empty =\n { $type ->\n [maximum] Se ignora el máximo vacío de la función.\n [minimum] Se ignora el mínimo vacío de la función.\n [extremum] Se ignora el extremo vacío de la función.\n [point] Se ignora el punto vacío de la función.\n *[other] Se ignora { $type } vacío de la función.\n }\n\nfunction-points-too-close = La función contiene dos puntos demasiado próximos entre sí. No se puede definir la función.\n\nfunction-iterates-input-output-mismatch =\n { $inputs ->\n [one] Las iteraciones de una función solo son posibles si el número de entradas es igual al número de salidas. Esta función tiene { $inputs } entrada y { $outputs ->\n [one] { $outputs } salida\n *[other] { $outputs } salidas\n }.\n *[other] Las iteraciones de una función solo son posibles si el número de entradas es igual al número de salidas. Esta función tiene { $inputs } entradas y { $outputs ->\n [one] { $outputs } salida\n *[other] { $outputs } salidas\n }.\n }\n\n## `<sequence>`\n\nsequence-invalid-length = Longitud de la secuencia no válida. Debe ser un entero no negativo.\n\nsequence-invalid-step = Paso de la secuencia no válido. Debe ser un número para una secuencia de tipo { $type }.\n\nsequence-invalid-endpoint-number = El valor de "{ $attribute }" de la secuencia numérica no es válido. Debe ser un número.\n\nsequence-invalid-endpoint-letters = El valor de "{ $attribute }" de la secuencia de letras no es válido. Debe ser una combinación de letras.\n\nsequence-invalid-endpoint = El valor de "{ $attribute }" de la secuencia no es válido.\n\nselect-from-sequence-coprime-not-numbers = Se ignora coprime porque no se están seleccionando números\n\nselect-from-sequence-coprime-with-exclude-combinations = Se ignora coprime porque se especificó excludeCombinations\n\n## Resolución de `target`\n\ntarget-not-found = Destino no válido para `<{ $source }>`: no se encuentra el destino.\n\ntarget-state-variable-not-found = Destino no válido para `<{ $source }>`: no se encuentra una variable de estado llamada "{ $property }" en un `<{ $component }>`.\n\n## `<odeSystem>`\n\node-system-variables-match-independent = Las variables de `<odeSystem>` deben ser distintas de la variable independiente.\n\node-system-duplicate-variable-names = No se pueden definir las funciones del lado derecho de la EDO con nombres de variables dependientes repetidos.\n\node-system-rhs-function-error = No se puede definir la función del lado derecho de la EDO. Error al crear la función de mathjs.\n\n## `<angle>`, `<parabola>` e `<intersection>`\n\nangle-too-many-lines = No se puede definir un ángulo entre { $count } rectas\n\nangle-invalid-through-point = Punto no válido en through de `<angle>`\n\nparabola-vertex-too-many-points = No está implementada una parábola con vértice que pase por más de 1 punto.\n\nparabola-too-many-points = No está implementada una parábola que pase por más de 3 puntos.\n\nintersection-too-many-items = No está implementada la intersección de más de dos objetos\n\n## Otros componentes matemáticos\n\nionic-compound-not-two-ions = No está implementado el compuesto iónico para algo distinto de dos iones.\n\nionic-compound-needs-cation-and-anion = El compuesto iónico solo está implementado para un catión y un anión.\n\nsolve-equations-cannot-evaluate = No se puede resolver la ecuación porque no se pudo evaluar: { $equation }\n\nmath-operators-operand-number-required = Se debe especificar operandNumber al extraer un operando matemático.\n\neigen-decomposition-failed = No se pudieron calcular los valores propios de la matriz\n';
46721
46721
  const BUNDLED_TRANSLATIONS = {
46722
46722
  es: {
46723
46723
  chrome: esChrome,
@@ -46763,6 +46763,20 @@ const DIAGNOSTIC_CODES = {
46763
46763
  "doenet-i0001": "line-segment-attributes-ignored-with-endpoints",
46764
46764
  "doenet-i0002": "line-segment-midpoint-offset-without-midpoint",
46765
46765
  "doenet-i0003": "line-segment-attributes-ignored-with-endpoint-and-midpoint",
46766
+ "doenet-i0004": "choice-input-indices-count-mismatch",
46767
+ "doenet-i0005": "pretzel-indices-count-mismatch",
46768
+ "doenet-i0006": "shuffle-indices-count-mismatch",
46769
+ "doenet-i0007": "indices-ignored-out-of-range",
46770
+ "doenet-i0008": "pretzel-indices-repeated",
46771
+ "doenet-i0009": "pretzel-circuit-first-index",
46772
+ "doenet-i0010": "variant-index-must-be-number",
46773
+ "doenet-i0011": "variant-index-must-be-integer",
46774
+ "doenet-i0012": "sequence-invalid-length",
46775
+ "doenet-i0013": "sequence-invalid-step",
46776
+ "doenet-i0014": "sequence-invalid-endpoint-number",
46777
+ "doenet-i0015": "sequence-invalid-endpoint-letters",
46778
+ "doenet-i0016": "sequence-invalid-endpoint",
46779
+ "doenet-i0017": "angle-too-many-lines",
46766
46780
  "doenet-w0001": "line-points-undetermined-dimensions",
46767
46781
  "doenet-w0002": "line-points-too-few-dimensions",
46768
46782
  "doenet-w0003": "line-points-depend-on-variables",
@@ -46770,7 +46784,64 @@ const DIAGNOSTIC_CODES = {
46770
46784
  "doenet-w0005": "ray-overprescribed-through",
46771
46785
  "doenet-w0006": "ray-dimension-mismatch",
46772
46786
  "doenet-w0007": "vector-overprescribed-head",
46773
- "doenet-w0008": "vector-dimension-mismatch"
46787
+ "doenet-w0008": "vector-dimension-mismatch",
46788
+ "doenet-w0009": "attract-to-without-nearest-point",
46789
+ "doenet-w0010": "constrain-to-without-nearest-point",
46790
+ "doenet-w0011": "constrain-to-interior-without-nearest-point",
46791
+ "doenet-w0012": "choice-input-label-position-ignored",
46792
+ "doenet-w0013": "string-children-need-type",
46793
+ "doenet-w0014": "invalid-type-defaulting-to-math",
46794
+ "doenet-w0015": "string-not-valid-component-to-arrange",
46795
+ "doenet-w0016": "invalid-type-defaulting-to-number",
46796
+ "doenet-w0017": "invalid-variable-value",
46797
+ "doenet-w0018": "side-by-side-absolute-widths",
46798
+ "doenet-w0019": "side-by-side-absolute-margins",
46799
+ "doenet-w0020": "side-by-side-no-block-child",
46800
+ "doenet-w0021": "label-for-ignored-on-graphical",
46801
+ "doenet-w0022": "label-for-must-resolve-to-one",
46802
+ "doenet-w0023": "label-for-unresolved",
46803
+ "doenet-w0024": "label-for-answer-with-authored-inputs",
46804
+ "doenet-w0025": "label-for-answer-without-input",
46805
+ "doenet-w0026": "label-for-must-reference-input-or-answer",
46806
+ "doenet-w0027": "circle-through-points-non-numerical",
46807
+ "doenet-w0028": "circle-too-many-through-points",
46808
+ "doenet-w0029": "circle-overprescribed-radius-center-points",
46809
+ "doenet-w0030": "circle-center-with-multiple-points",
46810
+ "doenet-w0031": "circle-radius-too-small",
46811
+ "doenet-w0032": "circle-radius-with-many-points",
46812
+ "doenet-w0033": "circle-invalid-center-or-through-points",
46813
+ "doenet-w0034": "circle-radius-center-with-multiple-points",
46814
+ "doenet-w0035": "circle-change-radius-non-numerical",
46815
+ "doenet-w0036": "circle-radius-with-points-non-numerical",
46816
+ "doenet-w0037": "circle-change-center-non-numerical",
46817
+ "doenet-w0038": "function-domain-insufficient-dimensions",
46818
+ "doenet-w0039": "function-domain-invalid-format",
46819
+ "doenet-w0040": "function-ignoring-non-numerical",
46820
+ "doenet-w0041": "function-ignoring-empty",
46821
+ "doenet-w0042": "function-points-too-close",
46822
+ "doenet-w0043": "target-not-found",
46823
+ "doenet-w0044": "target-state-variable-not-found",
46824
+ "doenet-w0045": "ode-system-variables-match-independent",
46825
+ "doenet-w0046": "ode-system-duplicate-variable-names",
46826
+ "doenet-w0047": "ode-system-rhs-function-error",
46827
+ "doenet-w0048": "angle-invalid-through-point",
46828
+ "doenet-w0049": "parabola-vertex-too-many-points",
46829
+ "doenet-w0050": "parabola-too-many-points",
46830
+ "doenet-w0051": "select-from-sequence-coprime-not-numbers",
46831
+ "doenet-w0052": "select-from-sequence-coprime-with-exclude-combinations",
46832
+ "doenet-w0053": "ionic-compound-not-two-ions",
46833
+ "doenet-w0054": "ionic-compound-needs-cation-and-anion",
46834
+ "doenet-w0055": "intersection-too-many-items",
46835
+ "doenet-w0056": "function-iterates-input-output-mismatch",
46836
+ "doenet-w0057": "solve-equations-cannot-evaluate",
46837
+ "doenet-w0058": "math-operators-operand-number-required",
46838
+ "doenet-w0059": "eigen-decomposition-failed",
46839
+ "doenet-a0001": "accessibility-short-description-or-decorative",
46840
+ "doenet-a0002": "accessibility-video-short-description",
46841
+ "doenet-a0003": "accessibility-input-short-description-or-label",
46842
+ "doenet-a0004": "accessibility-answer-input-short-description-or-label",
46843
+ "doenet-a0005": "accessibility-short-description-contains-math",
46844
+ "doenet-a0006": "accessibility-section-title-insufficient-contrast"
46774
46845
  };
46775
46846
  function isDiagnosticCode(code) {
46776
46847
  return Object.prototype.hasOwnProperty.call(DIAGNOSTIC_CODES, code);
@@ -77036,6 +77107,24 @@ function exprContainsVector(tree) {
77036
77107
  }
77037
77108
  return operands.some(exprContainsVector);
77038
77109
  }
77110
+ function codedDiagnostic({
77111
+ type,
77112
+ code,
77113
+ args,
77114
+ position: position2,
77115
+ sourceDoc,
77116
+ level
77117
+ }) {
77118
+ return {
77119
+ type,
77120
+ message: formatEnglishDiagnostic(code, args),
77121
+ code,
77122
+ ...args === void 0 ? {} : { args },
77123
+ ...position2 === void 0 ? {} : { position: position2 },
77124
+ ...sourceDoc === void 0 ? {} : { sourceDoc },
77125
+ ...level === void 0 ? {} : { level }
77126
+ };
77127
+ }
77039
77128
  class Label extends InlineComponent {
77040
77129
  constructor(args) {
77041
77130
  super(args);
@@ -77457,20 +77546,26 @@ class Label extends InlineComponent {
77457
77546
  let targetComponentIdx = null;
77458
77547
  if (hasForAttribute) {
77459
77548
  if (isGraphicalLabel) {
77460
- diagnostics2.push({
77461
- message: "The `for` attribute on graphical `<label>` is ignored.",
77462
- type: "warning"
77463
- });
77549
+ diagnostics2.push(
77550
+ codedDiagnostic({
77551
+ type: "warning",
77552
+ code: "doenet-w0021"
77553
+ })
77554
+ );
77464
77555
  } else if (forResolutions.length !== 1) {
77465
- diagnostics2.push({
77466
- message: "The `for` attribute on `<label>` must resolve to exactly one component.",
77467
- type: "warning"
77468
- });
77556
+ diagnostics2.push(
77557
+ codedDiagnostic({
77558
+ type: "warning",
77559
+ code: "doenet-w0022"
77560
+ })
77561
+ );
77469
77562
  } else if (forResolutions[0].unresolvedPath !== null) {
77470
- diagnostics2.push({
77471
- message: "The `for` attribute on `<label>` could not be resolved to a component.",
77472
- type: "warning"
77473
- });
77563
+ diagnostics2.push(
77564
+ codedDiagnostic({
77565
+ type: "warning",
77566
+ code: "doenet-w0023"
77567
+ })
77568
+ );
77474
77569
  } else {
77475
77570
  targetComponentIdx = forResolutions[0].componentIdx;
77476
77571
  }
@@ -77578,28 +77673,34 @@ class Label extends InlineComponent {
77578
77673
  };
77579
77674
  }
77580
77675
  if (answerHasAuthoredInputChildrenForLabel) {
77581
- diagnostics2.push({
77582
- message: "The `for` attribute on `<label>` references an `<answer>` with explicitly authored inputs; reference the input directly.",
77583
- type: "warning"
77584
- });
77676
+ diagnostics2.push(
77677
+ codedDiagnostic({
77678
+ type: "warning",
77679
+ code: "doenet-w0024"
77680
+ })
77681
+ );
77585
77682
  return {
77586
77683
  setValue: { forTargetInputComponentIdx: null },
77587
77684
  sendDiagnostics: diagnostics2
77588
77685
  };
77589
77686
  }
77590
- diagnostics2.push({
77591
- message: "The `for` attribute on `<label>` references an `<answer>` without an input to label.",
77592
- type: "warning"
77593
- });
77687
+ diagnostics2.push(
77688
+ codedDiagnostic({
77689
+ type: "warning",
77690
+ code: "doenet-w0025"
77691
+ })
77692
+ );
77594
77693
  return {
77595
77694
  setValue: { forTargetInputComponentIdx: null },
77596
77695
  sendDiagnostics: diagnostics2
77597
77696
  };
77598
77697
  }
77599
- diagnostics2.push({
77600
- message: "The `for` attribute on `<label>` must reference an input or an answer.",
77601
- type: "warning"
77602
- });
77698
+ diagnostics2.push(
77699
+ codedDiagnostic({
77700
+ type: "warning",
77701
+ code: "doenet-w0026"
77702
+ })
77703
+ );
77603
77704
  return {
77604
77705
  setValue: { forTargetInputComponentIdx: null },
77605
77706
  sendDiagnostics: diagnostics2
@@ -84978,10 +85079,10 @@ class ExtractMath extends MathOperatorOneInput {
84978
85079
  definition({ dependencyValues }) {
84979
85080
  if (dependencyValues.type === "operand") {
84980
85081
  if (dependencyValues.operandNumber === null) {
84981
- let warning = {
84982
- message: `Must specify a operandNumber when extracting a math operand.`,
84983
- type: "warning"
84984
- };
85082
+ let warning = codedDiagnostic({
85083
+ type: "warning",
85084
+ code: "doenet-w0058"
85085
+ });
84985
85086
  return {
84986
85087
  setValue: {
84987
85088
  mathOperator: () => Context.fromAst("_")
@@ -87014,13 +87115,15 @@ let Function$1 = class Function2 extends InlineComponent {
87014
87115
  numInputs
87015
87116
  );
87016
87117
  if (specifiedDomain.length !== numInputs) {
87017
- let warning = {
87118
+ let warning = codedDiagnostic({
87018
87119
  type: "warning",
87019
- message: `Insufficient dimensions for domain for function. Domain has ${specifiedDomain.length} interval${specifiedDomain.length === 1 ? "" : "s"} but the function has ${numInputs} input${numInputs === 1 ? "" : "s"}.`
87020
- };
87021
- if (globalDependencyValues.domainAttr.position) {
87022
- warning.position = globalDependencyValues.domainAttr.position;
87023
- }
87120
+ code: "doenet-w0038",
87121
+ args: {
87122
+ intervals: specifiedDomain.length,
87123
+ inputs: numInputs
87124
+ },
87125
+ position: globalDependencyValues.domainAttr.position || void 0
87126
+ });
87024
87127
  let infDomain = Context.fromAst([
87025
87128
  "interval",
87026
87129
  ["tuple", -Infinity, Infinity],
@@ -87040,13 +87143,11 @@ let Function$1 = class Function2 extends InlineComponent {
87040
87143
  Array.isArray(interval.tree) && interval.tree[0] === "interval"
87041
87144
  )
87042
87145
  )) {
87043
- let warning = {
87146
+ let warning = codedDiagnostic({
87044
87147
  type: "warning",
87045
- message: `Invalid format for domain for function.`
87046
- };
87047
- if (globalDependencyValues.domainAttr.position) {
87048
- warning.position = globalDependencyValues.domainAttr.position;
87049
- }
87148
+ code: "doenet-w0039",
87149
+ position: globalDependencyValues.domainAttr.position || void 0
87150
+ });
87050
87151
  let infDomain = Context.fromAst([
87051
87152
  "interval",
87052
87153
  ["tuple", -Infinity, Infinity],
@@ -90340,39 +90441,51 @@ function calculateInterpolationPoints({ dependencyValues, numerics }) {
90340
90441
  if (point2.x !== null) {
90341
90442
  x2 = point2.x.evaluate_to_constant();
90342
90443
  if (!Number.isFinite(x2)) {
90343
- diagnostics2.push({
90344
- message: `Ignoring non-numerical ${type} of function.`,
90345
- type: "warning"
90346
- });
90444
+ diagnostics2.push(
90445
+ codedDiagnostic({
90446
+ type: "warning",
90447
+ code: "doenet-w0040",
90448
+ args: { type }
90449
+ })
90450
+ );
90347
90451
  continue;
90348
90452
  }
90349
90453
  }
90350
90454
  if (point2.y !== null) {
90351
90455
  y2 = point2.y.evaluate_to_constant();
90352
90456
  if (!Number.isFinite(y2)) {
90353
- diagnostics2.push({
90354
- message: `Ignoring non-numerical ${type} of function.`,
90355
- type: "warning"
90356
- });
90457
+ diagnostics2.push(
90458
+ codedDiagnostic({
90459
+ type: "warning",
90460
+ code: "doenet-w0040",
90461
+ args: { type }
90462
+ })
90463
+ );
90357
90464
  continue;
90358
90465
  }
90359
90466
  }
90360
90467
  if (point2.slope !== null && point2.slope !== void 0) {
90361
90468
  slope = point2.slope.evaluate_to_constant();
90362
90469
  if (!Number.isFinite(slope)) {
90363
- diagnostics2.push({
90364
- message: `Ignoring non-numerical slope of function.`,
90365
- type: "warning"
90366
- });
90470
+ diagnostics2.push(
90471
+ codedDiagnostic({
90472
+ type: "warning",
90473
+ code: "doenet-w0040",
90474
+ args: { type: "slope" }
90475
+ })
90476
+ );
90367
90477
  slope = null;
90368
90478
  }
90369
90479
  }
90370
90480
  if (x2 === null) {
90371
90481
  if (y2 === null) {
90372
- diagnostics2.push({
90373
- message: `Ignoring empty ${type} of function.`,
90374
- type: "warning"
90375
- });
90482
+ diagnostics2.push(
90483
+ codedDiagnostic({
90484
+ type: "warning",
90485
+ code: "doenet-w0041",
90486
+ args: { type }
90487
+ })
90488
+ );
90376
90489
  continue;
90377
90490
  }
90378
90491
  pointsWithoutX.push({
@@ -90397,10 +90510,12 @@ function calculateInterpolationPoints({ dependencyValues, numerics }) {
90397
90510
  for (let ind = 0; ind < pointsWithX.length; ind++) {
90398
90511
  let p2 = pointsWithX[ind];
90399
90512
  if (p2.x <= xPrev + eps) {
90400
- diagnostics2.push({
90401
- message: `Function contains two points with locations too close together. Can't define function.`,
90402
- type: "warning"
90403
- });
90513
+ diagnostics2.push(
90514
+ codedDiagnostic({
90515
+ type: "warning",
90516
+ code: "doenet-w0042"
90517
+ })
90518
+ );
90404
90519
  return {
90405
90520
  setValue: { interpolationPoints: null },
90406
90521
  sendDiagnostics: diagnostics2
@@ -93747,7 +93862,7 @@ function addSectionTitleColorContrastDiagnostic({
93747
93862
  colorName: colorName2,
93748
93863
  textColor,
93749
93864
  canvasColor,
93750
- modeSuffix = ""
93865
+ mode = "light"
93751
93866
  }) {
93752
93867
  if (!authorSet || !colorValue) {
93753
93868
  return;
@@ -93758,11 +93873,22 @@ function addSectionTitleColorContrastDiagnostic({
93758
93873
  background: colorValue
93759
93874
  });
93760
93875
  if (ratio !== null && ratio < TEXT_CONTRAST_THRESHOLD) {
93761
- diagnostics2.push({
93762
- type: "accessibility",
93763
- level: 1,
93764
- message: `${colorName2} has insufficient contrast for the section heading text${modeSuffix} (${ratio.toFixed(2)}:1; requires at least ${TEXT_CONTRAST_THRESHOLD}:1).`
93765
- });
93876
+ diagnostics2.push(
93877
+ codedDiagnostic({
93878
+ type: "accessibility",
93879
+ level: 1,
93880
+ code: "doenet-a0006",
93881
+ args: {
93882
+ colorName: colorName2,
93883
+ // Numbers, not the strings they used to be formatted
93884
+ // into: a locale that writes 4,50 rather than 4.50 can
93885
+ // only do so if the value arrives as a number.
93886
+ ratio,
93887
+ threshold: TEXT_CONTRAST_THRESHOLD,
93888
+ mode
93889
+ }
93890
+ })
93891
+ );
93766
93892
  }
93767
93893
  }
93768
93894
  class SectioningComponent extends BlockComponent {
@@ -94632,7 +94758,7 @@ class SectioningComponent extends BlockComponent {
94632
94758
  colorName: darkSource?.colorName ?? stateKey,
94633
94759
  textColor: "#ffffff",
94634
94760
  canvasColor: CANVAS_DARK_MODE_COLOR,
94635
- modeSuffix: " (dark mode)"
94761
+ mode: "dark"
94636
94762
  });
94637
94763
  }
94638
94764
  }
@@ -94921,21 +95047,27 @@ class SectioningComponent extends BlockComponent {
94921
95047
  if (desiredVariant.index !== void 0) {
94922
95048
  let desiredVariantIndex = Number(desiredVariant.index);
94923
95049
  if (!Number.isFinite(desiredVariantIndex)) {
94924
- core2.addDiagnostic({
94925
- type: "info",
94926
- message: "Variant index " + desiredVariant.index + " must be a number",
94927
- position: serializedComponent.position,
94928
- sourceDoc: serializedComponent.sourceDoc
94929
- });
94930
- variantIndex = 1;
94931
- } else {
94932
- if (!Number.isInteger(desiredVariantIndex)) {
94933
- core2.addDiagnostic({
95050
+ core2.addDiagnostic(
95051
+ codedDiagnostic({
94934
95052
  type: "info",
94935
- message: "Variant index " + desiredVariant.index + " must be an integer",
95053
+ code: "doenet-i0010",
95054
+ args: { index: String(desiredVariant.index) },
94936
95055
  position: serializedComponent.position,
94937
95056
  sourceDoc: serializedComponent.sourceDoc
94938
- });
95057
+ })
95058
+ );
95059
+ variantIndex = 1;
95060
+ } else {
95061
+ if (!Number.isInteger(desiredVariantIndex)) {
95062
+ core2.addDiagnostic(
95063
+ codedDiagnostic({
95064
+ type: "info",
95065
+ code: "doenet-i0011",
95066
+ args: { index: String(desiredVariant.index) },
95067
+ position: serializedComponent.position,
95068
+ sourceDoc: serializedComponent.sourceDoc
95069
+ })
95070
+ );
94939
95071
  desiredVariantIndex = Math.round(desiredVariantIndex);
94940
95072
  }
94941
95073
  let indexFrom0 = (desiredVariantIndex - 1) % numVariants;
@@ -95886,14 +96018,13 @@ class ODESystem extends InlineComponent {
95886
96018
  if (variables2.some(
95887
96019
  (x2) => x2.equals(globalDependencyValues.independentVariable)
95888
96020
  )) {
95889
- const warning = {
95890
- type: "warning",
95891
- message: "Variables of `<odeSystem>` must be different than independent variable."
95892
- };
95893
- if (globalDependencyValues.variables?.position) {
95894
- warning.position = globalDependencyValues.variables.position;
95895
- }
95896
- diagnostics2.push(warning);
96021
+ diagnostics2.push(
96022
+ codedDiagnostic({
96023
+ type: "warning",
96024
+ code: "doenet-w0045",
96025
+ position: globalDependencyValues.variables?.position || void 0
96026
+ })
96027
+ );
95897
96028
  }
95898
96029
  if (validVariables.length < numDims) {
95899
96030
  validVariables.push(
@@ -96218,10 +96349,12 @@ class ODESystem extends InlineComponent {
96218
96349
  valid = false;
96219
96350
  }
96220
96351
  if ([...new Set(varNames)].length !== varNames.length) {
96221
- diagnostics2.push({
96222
- message: "Can't define ODE RHS functions with duplicate dependent variable names.",
96223
- type: "warning"
96224
- });
96352
+ diagnostics2.push(
96353
+ codedDiagnostic({
96354
+ type: "warning",
96355
+ code: "doenet-w0046"
96356
+ })
96357
+ );
96225
96358
  valid = false;
96226
96359
  }
96227
96360
  let fs;
@@ -96230,10 +96363,12 @@ class ODESystem extends InlineComponent {
96230
96363
  (x2) => x2.subscripts_to_strings().f()
96231
96364
  );
96232
96365
  } catch (e32) {
96233
- diagnostics2.push({
96234
- message: "Cannot define ODE RHS function. Error creating mathjs function.",
96235
- type: "warning"
96236
- });
96366
+ diagnostics2.push(
96367
+ codedDiagnostic({
96368
+ type: "warning",
96369
+ code: "doenet-w0047"
96370
+ })
96371
+ );
96237
96372
  valid = false;
96238
96373
  }
96239
96374
  if (!valid) {
@@ -101213,24 +101348,6 @@ function returnLineFamilyLabelPositionAttribute() {
101213
101348
  description: "Where the label sits along this line/curve."
101214
101349
  };
101215
101350
  }
101216
- function codedDiagnostic({
101217
- type,
101218
- code,
101219
- args,
101220
- position: position2,
101221
- sourceDoc,
101222
- level
101223
- }) {
101224
- return {
101225
- type,
101226
- message: formatEnglishDiagnostic(code, args),
101227
- code,
101228
- ...args === void 0 ? {} : { args },
101229
- ...position2 === void 0 ? {} : { position: position2 },
101230
- ...sourceDoc === void 0 ? {} : { sourceDoc },
101231
- ...level === void 0 ? {} : { level }
101232
- };
101233
- }
101234
101351
  class Line extends GraphicalComponent {
101235
101352
  constructor(args) {
101236
101353
  super(args);
@@ -110448,20 +110565,20 @@ class IonicCompound extends InlineComponent {
110448
110565
  (child) => child.stateValues.charge
110449
110566
  );
110450
110567
  if (charges.length !== 2) {
110451
- let warning = {
110452
- message: "Have not implemented ionic compound for anything other than two ions.",
110453
- type: "warning"
110454
- };
110568
+ let warning = codedDiagnostic({
110569
+ type: "warning",
110570
+ code: "doenet-w0053"
110571
+ });
110455
110572
  return {
110456
110573
  setValue: { ionicCompound: null },
110457
110574
  sendDiagnostics: [warning]
110458
110575
  };
110459
110576
  }
110460
110577
  if (!(charges[0] * charges[1] < 0)) {
110461
- let warning = {
110462
- message: "Ionic compound implemented only for one cation and one anion.",
110463
- type: "warning"
110464
- };
110578
+ let warning = codedDiagnostic({
110579
+ type: "warning",
110580
+ code: "doenet-w0054"
110581
+ });
110465
110582
  return {
110466
110583
  setValue: { ionicCompound: null },
110467
110584
  sendDiagnostics: [warning]
@@ -111698,10 +111815,13 @@ class ComponentWithSelectableType extends BaseComponent {
111698
111815
  if (!type) {
111699
111816
  type = "number";
111700
111817
  } else if (!["number", "letters", "math", "text", "boolean"].includes(type)) {
111701
- diagnostics2.push({
111702
- message: `Invalid type ${type}, setting type to number.`,
111703
- type: "warning"
111704
- });
111818
+ diagnostics2.push(
111819
+ codedDiagnostic({
111820
+ type: "warning",
111821
+ code: "doenet-w0016",
111822
+ args: { type }
111823
+ })
111824
+ );
111705
111825
  type = "number";
111706
111826
  }
111707
111827
  let componentType = type === "letters" ? "text" : type;
@@ -111766,10 +111886,16 @@ class ComponentWithSelectableType extends BaseComponent {
111766
111886
  } else if (!["number", "letters", "math", "text", "boolean"].includes(
111767
111887
  type
111768
111888
  )) {
111769
- diagnostics2.push({
111770
- message: `Invalid type ${type}, setting type to number.`,
111771
- type: "info"
111772
- });
111889
+ diagnostics2.push(
111890
+ codedDiagnostic({
111891
+ // Info here, a warning at the other three call
111892
+ // sites. The code names the situation, not the
111893
+ // severity, so they share it.
111894
+ type: "info",
111895
+ code: "doenet-w0016",
111896
+ args: { type }
111897
+ })
111898
+ );
111773
111899
  type = "number";
111774
111900
  }
111775
111901
  return { setValue: { type }, sendDiagnostics: diagnostics2 };
@@ -111868,10 +111994,13 @@ class ComponentListWithSelectableType extends ComponentWithSelectableType {
111868
111994
  } else if (!["number", "letters", "math", "text", "boolean"].includes(
111869
111995
  type
111870
111996
  )) {
111871
- diagnostics2.push({
111872
- message: `Invalid type ${type}, setting type to number.`,
111873
- type: "warning"
111874
- });
111997
+ diagnostics2.push(
111998
+ codedDiagnostic({
111999
+ type: "warning",
112000
+ code: "doenet-w0016",
112001
+ args: { type }
112002
+ })
112003
+ );
111875
112004
  type = "number";
111876
112005
  }
111877
112006
  let componentType = type === "letters" ? "text" : type;
@@ -112032,10 +112161,13 @@ class ComponentListOfListsWithSelectableType extends ComponentWithSelectableType
112032
112161
  if (!type) {
112033
112162
  type = "number";
112034
112163
  } else if (!["number", "letters", "math", "text", "boolean"].includes(type)) {
112035
- diagnostics2.push({
112036
- message: `Invalid type ${type}, setting type to number.`,
112037
- type: "warning"
112038
- });
112164
+ diagnostics2.push(
112165
+ codedDiagnostic({
112166
+ type: "warning",
112167
+ code: "doenet-w0016",
112168
+ args: { type }
112169
+ })
112170
+ );
112039
112171
  type = "number";
112040
112172
  }
112041
112173
  const newChildren = results.pieces.map((x2) => ({
@@ -112437,10 +112569,13 @@ class SideBySide extends BlockComponent {
112437
112569
  }
112438
112570
  }
112439
112571
  if (foundAbsolute) {
112440
- diagnostics2.push({
112441
- message: "`<sideBySide>` is not implemented for absolute measurements. Setting widths to relative.",
112442
- type: "warning"
112443
- });
112572
+ diagnostics2.push(
112573
+ codedDiagnostic({
112574
+ type: "warning",
112575
+ code: "doenet-w0018",
112576
+ args: { component: "sideBySide" }
112577
+ })
112578
+ );
112444
112579
  }
112445
112580
  widthsAbsolute = false;
112446
112581
  allWidthsSpecified = allWidthsSpecified.map(
@@ -112570,10 +112705,13 @@ class SideBySide extends BlockComponent {
112570
112705
  );
112571
112706
  }
112572
112707
  if (secondMarginAbsolute || marginsAbsolute) {
112573
- diagnostics2.push({
112574
- message: "`<sideBySide>` is not implemented for absolute measurements. Setting margins to relative.",
112575
- type: "warning"
112576
- });
112708
+ diagnostics2.push(
112709
+ codedDiagnostic({
112710
+ type: "warning",
112711
+ code: "doenet-w0019",
112712
+ args: { component: "sideBySide" }
112713
+ })
112714
+ );
112577
112715
  }
112578
112716
  marginsAbsolute = false;
112579
112717
  return {
@@ -112705,10 +112843,13 @@ class SideBySide extends BlockComponent {
112705
112843
  } else if (dependencyValues.numPanels === 1) {
112706
112844
  allMargins[1] = 100 - (allMargins[0] + allWidths[0]);
112707
112845
  } else {
112708
- diagnostics2.push({
112709
- message: "Invalid `<sideBySide>`: it must have at least one block child.",
112710
- type: "warning"
112711
- });
112846
+ diagnostics2.push(
112847
+ codedDiagnostic({
112848
+ type: "warning",
112849
+ code: "doenet-w0020",
112850
+ args: { component: "sideBySide" }
112851
+ })
112852
+ );
112712
112853
  }
112713
112854
  }
112714
112855
  }
@@ -113445,10 +113586,13 @@ class SbsGroup extends BlockComponent {
113445
113586
  }
113446
113587
  }
113447
113588
  if (foundAbsolute) {
113448
- diagnostics2.push({
113449
- message: "`<sbsGroup>` is not implemented for absolute measurements. Setting widths to relative.",
113450
- type: "warning"
113451
- });
113589
+ diagnostics2.push(
113590
+ codedDiagnostic({
113591
+ type: "warning",
113592
+ code: "doenet-w0018",
113593
+ args: { component: "sbsGroup" }
113594
+ })
113595
+ );
113452
113596
  }
113453
113597
  widthsAbsolute = false;
113454
113598
  return {
@@ -113637,10 +113781,13 @@ class SbsGroup extends BlockComponent {
113637
113781
  }
113638
113782
  }
113639
113783
  if (foundAbsolute) {
113640
- diagnostics2.push({
113641
- message: "`<sbsGroup>` is not implemented for absolute measurements. Setting margins to relative.",
113642
- type: "warning"
113643
- });
113784
+ diagnostics2.push(
113785
+ codedDiagnostic({
113786
+ type: "warning",
113787
+ code: "doenet-w0019",
113788
+ args: { component: "sbsGroup" }
113789
+ })
113790
+ );
113644
113791
  }
113645
113792
  marginsAbsolute = false;
113646
113793
  return {
@@ -113771,10 +113918,13 @@ class SbsGroup extends BlockComponent {
113771
113918
  } else if (dependencyValues.maxNPanelsPerRow === 1) {
113772
113919
  allMargins[1] = 100 - (allMargins[0] + allWidths[0]);
113773
113920
  } else {
113774
- diagnostics2.push({
113775
- message: "Invalid `<sbsGroup>`: it must have at least one block child.",
113776
- type: "warning"
113777
- });
113921
+ diagnostics2.push(
113922
+ codedDiagnostic({
113923
+ type: "warning",
113924
+ code: "doenet-w0020",
113925
+ args: { component: "sbsGroup" }
113926
+ })
113927
+ );
113778
113928
  }
113779
113929
  }
113780
113930
  }
@@ -115433,12 +115583,21 @@ class Input extends InlineComponent {
115433
115583
  dependencyValues.externalLabelsReferencingInputByFor?.length
115434
115584
  );
115435
115585
  if (shortDescription === "" && !dependencyValues.label && !hasExternalForLabel) {
115436
- let objectNeedingLabel = dependencyValues.createdFromSugar && dependencyValues.answerAncestor ? "an `<answer>` creating an input" : `\`<${componentClass.componentType}>\``;
115437
- diagnostics2.push({
115438
- type: "accessibility",
115439
- level: 1,
115440
- message: `For accessibility, ${objectNeedingLabel} must have a short description or a label.`
115441
- });
115586
+ const createdByAnswer = dependencyValues.createdFromSugar && dependencyValues.answerAncestor;
115587
+ diagnostics2.push(
115588
+ createdByAnswer ? codedDiagnostic({
115589
+ type: "accessibility",
115590
+ level: 1,
115591
+ code: "doenet-a0004"
115592
+ }) : codedDiagnostic({
115593
+ type: "accessibility",
115594
+ level: 1,
115595
+ code: "doenet-a0003",
115596
+ args: {
115597
+ component: componentClass.componentType
115598
+ }
115599
+ })
115600
+ );
115442
115601
  }
115443
115602
  return {
115444
115603
  setValue: { shortDescription },
@@ -120696,21 +120855,27 @@ class Document extends BaseComponent {
120696
120855
  if (desiredVariant.index !== void 0) {
120697
120856
  let desiredVariantIndex = Number(desiredVariant.index);
120698
120857
  if (!Number.isFinite(desiredVariantIndex)) {
120699
- core2.addDiagnostic({
120700
- type: "info",
120701
- message: "Variant index " + desiredVariant.index + " must be a number",
120702
- position: serializedComponent.position,
120703
- sourceDoc: serializedComponent.sourceDoc
120704
- });
120705
- variantIndex = 1;
120706
- } else {
120707
- if (!Number.isInteger(desiredVariantIndex)) {
120708
- core2.addDiagnostic({
120858
+ core2.addDiagnostic(
120859
+ codedDiagnostic({
120709
120860
  type: "info",
120710
- message: "Variant index " + desiredVariant.index + " must be an integer",
120861
+ code: "doenet-i0010",
120862
+ args: { index: String(desiredVariant.index) },
120711
120863
  position: serializedComponent.position,
120712
120864
  sourceDoc: serializedComponent.sourceDoc
120713
- });
120865
+ })
120866
+ );
120867
+ variantIndex = 1;
120868
+ } else {
120869
+ if (!Number.isInteger(desiredVariantIndex)) {
120870
+ core2.addDiagnostic(
120871
+ codedDiagnostic({
120872
+ type: "info",
120873
+ code: "doenet-i0011",
120874
+ args: { index: String(desiredVariant.index) },
120875
+ position: serializedComponent.position,
120876
+ sourceDoc: serializedComponent.sourceDoc
120877
+ })
120878
+ );
120714
120879
  desiredVariantIndex = Math.round(desiredVariantIndex);
120715
120880
  }
120716
120881
  let indexFrom0 = (desiredVariantIndex - 1) % numVariants;
@@ -131395,9 +131560,11 @@ class Circle extends Curve {
131395
131560
  }),
131396
131561
  definition: function({ dependencyValues }) {
131397
131562
  if (dependencyValues.haveNonNumericalThroughPoints) {
131398
- let message = "Haven't implemented `<circle>` through " + dependencyValues.numThroughPoints + " points";
131399
- message += " in case where the points don't have numerical values.";
131400
- let warning = { message, type: "warning" };
131563
+ let warning = codedDiagnostic({
131564
+ type: "warning",
131565
+ code: "doenet-w0027",
131566
+ args: { count: dependencyValues.numThroughPoints }
131567
+ });
131401
131568
  return {
131402
131569
  setValue: {
131403
131570
  numericalRadiusCalculatedWithCenter: null,
@@ -131469,10 +131636,10 @@ class Circle extends Curve {
131469
131636
  }
131470
131637
  };
131471
131638
  } else if (dependencyValues.numThroughPoints > 3) {
131472
- let warning = {
131473
- message: "Cannot calculate circle through more than 3 points.",
131474
- type: "warning"
131475
- };
131639
+ let warning = codedDiagnostic({
131640
+ type: "warning",
131641
+ code: "doenet-w0028"
131642
+ });
131476
131643
  return {
131477
131644
  setValue: {
131478
131645
  numericalRadiusCalculatedWithCenter: null,
@@ -131507,10 +131674,10 @@ class Circle extends Curve {
131507
131674
  }),
131508
131675
  definition({ dependencyValues }) {
131509
131676
  if (dependencyValues.havePrescribedCenter && dependencyValues.havePrescribedRadius && dependencyValues.numThroughPoints > 0) {
131510
- let warning = {
131511
- message: "Cannot calculate circle with specified radius, center and through points.",
131512
- type: "warning"
131513
- };
131677
+ let warning = codedDiagnostic({
131678
+ type: "warning",
131679
+ code: "doenet-w0029"
131680
+ });
131514
131681
  return {
131515
131682
  setValue: { haveCenterRadiusPoints: true },
131516
131683
  sendDiagnostics: [warning]
@@ -131654,10 +131821,10 @@ class Circle extends Curve {
131654
131821
  );
131655
131822
  return { setValue: { numericalRadius } };
131656
131823
  } else {
131657
- let warning = {
131658
- message: "Cannot calculate circle with specified center through more than 1 point.",
131659
- type: "warning"
131660
- };
131824
+ let warning = codedDiagnostic({
131825
+ type: "warning",
131826
+ code: "doenet-w0030"
131827
+ });
131661
131828
  return {
131662
131829
  setValue: { numericalRadius: NaN },
131663
131830
  sendDiagnostics: [warning]
@@ -131959,10 +132126,18 @@ class Circle extends Curve {
131959
132126
  let r22 = r2 * r2;
131960
132127
  if (r2 < 0 || 4 * r22 < dist2) {
131961
132128
  let dist3 = Math.round(Math.sqrt(dist2) * 100) / 100;
131962
- let warning = {
131963
- message: `Cannot calculate circle: given that the distance between the two points is ${dist3}, the specified radius ${r2} is too small.`,
131964
- type: "warning"
131965
- };
132129
+ let warning = codedDiagnostic({
132130
+ type: "warning",
132131
+ code: "doenet-w0031",
132132
+ // Strings rather than numbers: the radius is
132133
+ // the author's own value quoted back, and a
132134
+ // number argument is formatted as a quantity,
132135
+ // which would round 0.0001 away to 0.
132136
+ args: {
132137
+ distance: String(dist3),
132138
+ radius: String(r2)
132139
+ }
132140
+ });
131966
132141
  return {
131967
132142
  setValue: { numericalCenter: [NaN, NaN] },
131968
132143
  sendDiagnostics: [warning]
@@ -131979,10 +132154,10 @@ class Circle extends Curve {
131979
132154
  setValue: { numericalCenter: [centerx, centery] }
131980
132155
  };
131981
132156
  } else {
131982
- let warning = {
131983
- message: "Cannot create circle through more than two points with a specified radius.",
131984
- type: "warning"
131985
- };
132157
+ let warning = codedDiagnostic({
132158
+ type: "warning",
132159
+ code: "doenet-w0032"
132160
+ });
131986
132161
  return {
131987
132162
  setValue: { numericalCenter: [NaN, NaN] },
131988
132163
  sendDiagnostics: [warning]
@@ -132236,20 +132411,20 @@ class Circle extends Curve {
132236
132411
  let radius = ptx.subtract(ctx).pow(2).add(pty.subtract(cty).pow(2)).pow(0.5).simplify();
132237
132412
  return { setValue: { radius } };
132238
132413
  } catch (e32) {
132239
- let warning = {
132240
- message: "Invalid center or through points of circle.",
132241
- type: "warning"
132242
- };
132414
+ let warning = codedDiagnostic({
132415
+ type: "warning",
132416
+ code: "doenet-w0033"
132417
+ });
132243
132418
  return {
132244
132419
  setValue: { radius: Context.fromAst("_") },
132245
132420
  sendDiagnostics: [warning]
132246
132421
  };
132247
132422
  }
132248
132423
  } else {
132249
- let warning = {
132250
- message: "Cannot calculate radius of circle with specified center through more than 1 point.",
132251
- type: "warning"
132252
- };
132424
+ let warning = codedDiagnostic({
132425
+ type: "warning",
132426
+ code: "doenet-w0034"
132427
+ });
132253
132428
  return {
132254
132429
  setValue: { radius: Context.fromAst("_") },
132255
132430
  sendDiagnostics: [warning]
@@ -132313,10 +132488,10 @@ class Circle extends Curve {
132313
132488
  instructions
132314
132489
  };
132315
132490
  } else {
132316
- let warning = {
132317
- message: "Cannot change radius of circle with non-numerical through points",
132318
- type: "warning"
132319
- };
132491
+ let warning = codedDiagnostic({
132492
+ type: "warning",
132493
+ code: "doenet-w0035"
132494
+ });
132320
132495
  return { success: false, sendDiagnostics: [warning] };
132321
132496
  }
132322
132497
  }
@@ -132587,10 +132762,12 @@ class Circle extends Curve {
132587
132762
  } else {
132588
132763
  let diagnostics2 = [];
132589
132764
  if (globalDependencyValues.haveNonNumericalPrescribedRadius || globalDependencyValues.haveNonNumericalThroughPoints) {
132590
- diagnostics2.push({
132591
- message: "Cannot create circle through more than one point with specified radius when don't have numerical values.",
132592
- type: "warning"
132593
- });
132765
+ diagnostics2.push(
132766
+ codedDiagnostic({
132767
+ type: "warning",
132768
+ code: "doenet-w0036"
132769
+ })
132770
+ );
132594
132771
  }
132595
132772
  return {
132596
132773
  setValue: {
@@ -132696,10 +132873,10 @@ class Circle extends Curve {
132696
132873
  instructions
132697
132874
  };
132698
132875
  } else {
132699
- let warning = {
132700
- message: "Haven't implemented changing center of circle through points with non numerical values.",
132701
- type: "warning"
132702
- };
132876
+ let warning = codedDiagnostic({
132877
+ type: "warning",
132878
+ code: "doenet-w0037"
132879
+ });
132703
132880
  return { success: false, sendDiagnostics: [warning] };
132704
132881
  }
132705
132882
  }
@@ -133600,10 +133777,10 @@ class Parabola extends Curve {
133600
133777
  }
133601
133778
  return { setValue: { a: a2, b: b2, c: c2, realValued } };
133602
133779
  } else {
133603
- let warning = {
133604
- message: "Haven't implemented parabola with vertex through more than 1 point.",
133605
- type: "warning"
133606
- };
133780
+ let warning = codedDiagnostic({
133781
+ type: "warning",
133782
+ code: "doenet-w0049"
133783
+ });
133607
133784
  return {
133608
133785
  setValue: {
133609
133786
  a: NaN,
@@ -133746,10 +133923,10 @@ class Parabola extends Curve {
133746
133923
  }
133747
133924
  return { setValue: { a: a2, b: b2, c: c2, realValued } };
133748
133925
  } else {
133749
- let warning = {
133750
- message: "Haven't implemented parabola through more than 3 points.",
133751
- type: "warning"
133752
- };
133926
+ let warning = codedDiagnostic({
133927
+ type: "warning",
133928
+ code: "doenet-w0050"
133929
+ });
133753
133930
  return {
133754
133931
  setValue: {
133755
133932
  a: NaN,
@@ -139566,10 +139743,13 @@ class Angle extends GraphicalComponent {
139566
139743
  arrayDefinitionByKey({ globalDependencyValues }) {
139567
139744
  if (globalDependencyValues.lineChildren) {
139568
139745
  if (globalDependencyValues.lineChildren.length > 2) {
139569
- let warning = {
139570
- message: `Cannot define an angle between ${globalDependencyValues.lineChildren.length} lines`,
139571
- type: "info"
139572
- };
139746
+ let warning = codedDiagnostic({
139747
+ type: "info",
139748
+ code: "doenet-i0017",
139749
+ args: {
139750
+ count: globalDependencyValues.lineChildren.length
139751
+ }
139752
+ });
139573
139753
  let points2 = {};
139574
139754
  for (let i2 = 0; i2 < 3; i2++) {
139575
139755
  for (let j2 = 0; j2 < 2; j2++) {
@@ -139709,13 +139889,13 @@ class Angle extends GraphicalComponent {
139709
139889
  }
139710
139890
  const diagnostics2 = [];
139711
139891
  if (foundBadThroughPoint) {
139712
- diagnostics2.push({
139713
- message: "Invalid point in through of `<angle>`",
139714
- type: "warning"
139715
- });
139716
- if (globalDependencyValues.throughAttr.position) {
139717
- diagnostics2[diagnostics2.length - 1].position = globalDependencyValues.throughAttr.position;
139718
- }
139892
+ diagnostics2.push(
139893
+ codedDiagnostic({
139894
+ type: "warning",
139895
+ code: "doenet-w0048",
139896
+ position: globalDependencyValues.throughAttr.position || void 0
139897
+ })
139898
+ );
139719
139899
  }
139720
139900
  if (numPointsSpecified === 0) {
139721
139901
  points["0,0"] = Context.fromAst(1);
@@ -145132,11 +145312,13 @@ class Choiceinput extends Input {
145132
145312
  }
145133
145313
  const diagnostics2 = [];
145134
145314
  if (dependencyValues.labelPositionAttr && !isInline) {
145135
- diagnostics2.push({
145136
- message: "labelPosition is ignored for non-inline choiceInput",
145137
- type: "warning",
145138
- position: dependencyValues.labelPositionAttr.position
145139
- });
145315
+ diagnostics2.push(
145316
+ codedDiagnostic({
145317
+ type: "warning",
145318
+ code: "doenet-w0012",
145319
+ position: dependencyValues.labelPositionAttr.position
145320
+ })
145321
+ );
145140
145322
  }
145141
145323
  return {
145142
145324
  setValue,
@@ -145206,10 +145388,12 @@ class Choiceinput extends Input {
145206
145388
  let desiredChoiceOrder = dependencyValues.variants?.desiredVariant?.indices;
145207
145389
  if (desiredChoiceOrder !== void 0) {
145208
145390
  if (desiredChoiceOrder.length !== numChoices) {
145209
- diagnostics2.push({
145210
- message: "Ignoring indices specified for choiceInput as number of indices doesn't match number of choice children.",
145211
- type: "info"
145212
- });
145391
+ diagnostics2.push(
145392
+ codedDiagnostic({
145393
+ type: "info",
145394
+ code: "doenet-i0004"
145395
+ })
145396
+ );
145213
145397
  } else {
145214
145398
  desiredChoiceOrder = desiredChoiceOrder.map(Number);
145215
145399
  if (!desiredChoiceOrder.every(Number.isInteger)) {
@@ -145220,10 +145404,13 @@ class Choiceinput extends Input {
145220
145404
  if (!desiredChoiceOrder.every(
145221
145405
  (x2) => x2 >= 1 && x2 <= numChoices
145222
145406
  )) {
145223
- diagnostics2.push({
145224
- message: "Ignoring indices specified for choiceInput as some indices out of range.",
145225
- type: "info"
145226
- });
145407
+ diagnostics2.push(
145408
+ codedDiagnostic({
145409
+ type: "info",
145410
+ code: "doenet-i0007",
145411
+ args: { component: "choiceInput" }
145412
+ })
145413
+ );
145227
145414
  } else {
145228
145415
  return {
145229
145416
  setValue: {
@@ -151907,11 +152094,14 @@ let Graph$1 = class Graph extends BlockComponent {
151907
152094
  shortDescription = shortDescriptionChild.stateValues.text.trim();
151908
152095
  }
151909
152096
  if (shortDescription === "" && !dependencyValues.decorative) {
151910
- diagnostics2.push({
151911
- type: "accessibility",
151912
- level: 1,
151913
- message: "For accessibility, `<graph>` must either have a short description or be specified as decorative."
151914
- });
152097
+ diagnostics2.push(
152098
+ codedDiagnostic({
152099
+ type: "accessibility",
152100
+ level: 1,
152101
+ code: "doenet-a0001",
152102
+ args: { component: "graph" }
152103
+ })
152104
+ );
151915
152105
  }
151916
152106
  return {
151917
152107
  setValue: { shortDescription },
@@ -154838,10 +155028,12 @@ function returnStandardSequenceStateVariableDefinitions() {
154838
155028
  let validSequence = true;
154839
155029
  if (dependencyValues.specifiedLength !== null) {
154840
155030
  if (!Number.isInteger(dependencyValues.specifiedLength) || dependencyValues.specifiedLength < 0) {
154841
- diagnostics2.push({
154842
- message: "Invalid length of sequence. Must be a non-negative integer.",
154843
- type: "info"
154844
- });
155031
+ diagnostics2.push(
155032
+ codedDiagnostic({
155033
+ type: "info",
155034
+ code: "doenet-i0012"
155035
+ })
155036
+ );
154845
155037
  validSequence = false;
154846
155038
  }
154847
155039
  }
@@ -154851,10 +155043,13 @@ function returnStandardSequenceStateVariableDefinitions() {
154851
155043
  dependencyValues.specifiedStep
154852
155044
  );
154853
155045
  if (!Number.isFinite(numericalStep)) {
154854
- diagnostics2.push({
154855
- message: "Invalid step of sequence. Must be a number for sequence of type " + dependencyValues.type + ".",
154856
- type: "info"
154857
- });
155046
+ diagnostics2.push(
155047
+ codedDiagnostic({
155048
+ type: "info",
155049
+ code: "doenet-i0013",
155050
+ args: { type: dependencyValues.type }
155051
+ })
155052
+ );
154858
155053
  validSequence = false;
154859
155054
  }
154860
155055
  }
@@ -154865,26 +155060,35 @@ function returnStandardSequenceStateVariableDefinitions() {
154865
155060
  dependencyValues.specifiedFrom
154866
155061
  );
154867
155062
  if (!Number.isFinite(numericalFrom)) {
154868
- diagnostics2.push({
154869
- message: `Invalid "from" of number sequence. Must be a number.`,
154870
- type: "info"
154871
- });
155063
+ diagnostics2.push(
155064
+ codedDiagnostic({
155065
+ type: "info",
155066
+ code: "doenet-i0014",
155067
+ args: { attribute: "from" }
155068
+ })
155069
+ );
154872
155070
  validSequence = false;
154873
155071
  }
154874
155072
  } else if (dependencyValues.type === "letters") {
154875
155073
  if (lettersToNumber(dependencyValues.specifiedFrom) === void 0) {
154876
- diagnostics2.push({
154877
- message: `Invalid "from" of letters sequence. Must be a letter combination.`,
154878
- type: "info"
154879
- });
155074
+ diagnostics2.push(
155075
+ codedDiagnostic({
155076
+ type: "info",
155077
+ code: "doenet-i0015",
155078
+ args: { attribute: "from" }
155079
+ })
155080
+ );
154880
155081
  validSequence = false;
154881
155082
  }
154882
155083
  } else {
154883
155084
  if (Number.isNaN(dependencyValues.specifiedFrom.tree)) {
154884
- diagnostics2.push({
154885
- message: `Invalid "from" of sequence.`,
154886
- type: "info"
154887
- });
155085
+ diagnostics2.push(
155086
+ codedDiagnostic({
155087
+ type: "info",
155088
+ code: "doenet-i0016",
155089
+ args: { attribute: "from" }
155090
+ })
155091
+ );
154888
155092
  validSequence = false;
154889
155093
  }
154890
155094
  }
@@ -154895,26 +155099,35 @@ function returnStandardSequenceStateVariableDefinitions() {
154895
155099
  dependencyValues.specifiedTo
154896
155100
  );
154897
155101
  if (!Number.isFinite(numericalTo)) {
154898
- diagnostics2.push({
154899
- message: `Invalid "to" of number sequence. Must be a number.`,
154900
- type: "info"
154901
- });
155102
+ diagnostics2.push(
155103
+ codedDiagnostic({
155104
+ type: "info",
155105
+ code: "doenet-i0014",
155106
+ args: { attribute: "to" }
155107
+ })
155108
+ );
154902
155109
  validSequence = false;
154903
155110
  }
154904
155111
  } else if (dependencyValues.type === "letters") {
154905
155112
  if (lettersToNumber(dependencyValues.specifiedTo) === void 0) {
154906
- diagnostics2.push({
154907
- message: `Invalid "to" of letters sequence. Must be a letter combination.`,
154908
- type: "info"
154909
- });
155113
+ diagnostics2.push(
155114
+ codedDiagnostic({
155115
+ type: "info",
155116
+ code: "doenet-i0015",
155117
+ args: { attribute: "to" }
155118
+ })
155119
+ );
154910
155120
  validSequence = false;
154911
155121
  }
154912
155122
  } else {
154913
155123
  if (Number.isNaN(dependencyValues.specifiedTo.tree)) {
154914
- diagnostics2.push({
154915
- message: `Invalid "to" of sequence.`,
154916
- type: "info"
154917
- });
155124
+ diagnostics2.push(
155125
+ codedDiagnostic({
155126
+ type: "info",
155127
+ code: "doenet-i0016",
155128
+ args: { attribute: "to" }
155129
+ })
155130
+ );
154918
155131
  validSequence = false;
154919
155132
  }
154920
155133
  }
@@ -158558,14 +158771,14 @@ class ConstrainTo extends ConstraintComponent {
158558
158771
  let diagnostics2 = [];
158559
158772
  for (let child of dependencyValues.graphicalChildren) {
158560
158773
  if (!child.stateValues.nearestPoint) {
158561
- const warning = {
158562
- type: "warning",
158563
- message: `Cannot constrain to a \`<${child.componentType}>\` as it doesn't have a nearestPoint state variable.`
158564
- };
158565
- if (child.position) {
158566
- warning.position = child.position;
158567
- }
158568
- diagnostics2.push(warning);
158774
+ diagnostics2.push(
158775
+ codedDiagnostic({
158776
+ type: "warning",
158777
+ code: "doenet-w0010",
158778
+ args: { component: child.componentType },
158779
+ position: child.position || void 0
158780
+ })
158781
+ );
158569
158782
  continue;
158570
158783
  }
158571
158784
  nearestPointFunctions.push(child.stateValues.nearestPoint);
@@ -158785,14 +158998,14 @@ class AttractTo extends ConstraintComponent {
158785
158998
  let diagnostics2 = [];
158786
158999
  for (let child of dependencyValues.graphicalChildren) {
158787
159000
  if (!child.stateValues.nearestPoint) {
158788
- const warning = {
158789
- type: "warning",
158790
- message: `Cannot attract to a \`<${child.componentType}>\` as it doesn't have a nearestPoint state variable.`
158791
- };
158792
- if (child.position) {
158793
- warning.position = child.position;
158794
- }
158795
- diagnostics2.push(warning);
159001
+ diagnostics2.push(
159002
+ codedDiagnostic({
159003
+ type: "warning",
159004
+ code: "doenet-w0009",
159005
+ args: { component: child.componentType },
159006
+ position: child.position || void 0
159007
+ })
159008
+ );
158796
159009
  continue;
158797
159010
  }
158798
159011
  nearestPointFunctions.push(child.stateValues.nearestPoint);
@@ -159143,14 +159356,14 @@ class ConstrainToInterior extends ConstraintComponent {
159143
159356
  let diagnostics2 = [];
159144
159357
  for (let child of dependencyValues.graphicalChildren) {
159145
159358
  if (!child.stateValues.nearestPoint) {
159146
- const warning = {
159147
- type: "warning",
159148
- message: `Cannot constrain to interior of a \`<${child.componentType}>\` as it doesn't have a nearestPoint state variable.`
159149
- };
159150
- if (child.position) {
159151
- warning.position = child.position;
159152
- }
159153
- diagnostics2.push(warning);
159359
+ diagnostics2.push(
159360
+ codedDiagnostic({
159361
+ type: "warning",
159362
+ code: "doenet-w0011",
159363
+ args: { component: child.componentType },
159364
+ position: child.position || void 0
159365
+ })
159366
+ );
159154
159367
  continue;
159155
159368
  }
159156
159369
  let fs = { nearestPoint: child.stateValues.nearestPoint };
@@ -159419,10 +159632,12 @@ class Intersection extends CompositeComponent {
159419
159632
  if (totNums < 2) {
159420
159633
  return { replacements: [], diagnostics: diagnostics2, nComponents };
159421
159634
  } else if (totNums > 2) {
159422
- diagnostics2.push({
159423
- message: "Haven't implemented intersection for more than two items",
159424
- type: "warning"
159425
- });
159635
+ diagnostics2.push(
159636
+ codedDiagnostic({
159637
+ type: "warning",
159638
+ code: "doenet-w0055"
159639
+ })
159640
+ );
159426
159641
  return { replacements: [], diagnostics: diagnostics2, nComponents };
159427
159642
  }
159428
159643
  let points = [];
@@ -202157,10 +202372,12 @@ class SelectFromSequence extends Sequence {
202157
202372
  definition: function({ dependencyValues }) {
202158
202373
  const diagnostics2 = [];
202159
202374
  if (dependencyValues.coprime && dependencyValues.type !== "number") {
202160
- diagnostics2.push({
202161
- message: "coprime ignored since not selecting numbers",
202162
- type: "warning"
202163
- });
202375
+ diagnostics2.push(
202376
+ codedDiagnostic({
202377
+ type: "warning",
202378
+ code: "doenet-w0051"
202379
+ })
202380
+ );
202164
202381
  }
202165
202382
  if (dependencyValues.excludeCombinations !== null) {
202166
202383
  let excludedCombinations = dependencyValues.excludeCombinations.stateValues.lists.map(
@@ -202180,10 +202397,12 @@ class SelectFromSequence extends Sequence {
202180
202397
  }
202181
202398
  }
202182
202399
  if (dependencyValues.coprime) {
202183
- diagnostics2.push({
202184
- message: "coprime ignored since excludeCombinations specified",
202185
- type: "warning"
202186
- });
202400
+ diagnostics2.push(
202401
+ codedDiagnostic({
202402
+ type: "warning",
202403
+ code: "doenet-w0052"
202404
+ })
202405
+ );
202187
202406
  }
202188
202407
  }
202189
202408
  return {
@@ -204690,10 +204909,13 @@ class AnimateFromSequence extends BaseComponent {
204690
204909
  }
204691
204910
  let diagnostics2 = [];
204692
204911
  if (targetIdentities === null || targetIdentities.length === 0) {
204693
- diagnostics2.push({
204694
- message: "Invalid target for `<animateFromSequence>`: cannot find target.",
204695
- type: "warning"
204696
- });
204912
+ diagnostics2.push(
204913
+ codedDiagnostic({
204914
+ type: "warning",
204915
+ code: "doenet-w0043",
204916
+ args: { source: "animateFromSequence" }
204917
+ })
204918
+ );
204697
204919
  }
204698
204920
  return {
204699
204921
  setValue: { targetIdentities },
@@ -204760,11 +204982,13 @@ class AnimateFromSequence extends BaseComponent {
204760
204982
  for (let ind in dependencyValues.targetIdentities) {
204761
204983
  let target = dependencyValues["target" + ind];
204762
204984
  if (target == null) {
204763
- let message = "Invalid target for `<animateFromSequence>`: cannot find target.";
204764
- diagnostics2.push({
204765
- message,
204766
- type: "warning"
204767
- });
204985
+ diagnostics2.push(
204986
+ codedDiagnostic({
204987
+ type: "warning",
204988
+ code: "doenet-w0043",
204989
+ args: { source: "animateFromSequence" }
204990
+ })
204991
+ );
204768
204992
  continue;
204769
204993
  }
204770
204994
  targets.push(target);
@@ -204776,17 +205000,29 @@ class AnimateFromSequence extends BaseComponent {
204776
205000
  prop += `[idx]`;
204777
205001
  }
204778
205002
  }
204779
- let message = `Invalid target for \`<animateFromSequence>\`: cannot find a state variable named "${prop}" on a \`<${target.componentType}>\`.`;
204780
- diagnostics2.push({
204781
- message,
204782
- type: "warning"
204783
- });
205003
+ diagnostics2.push(
205004
+ codedDiagnostic({
205005
+ type: "warning",
205006
+ code: "doenet-w0044",
205007
+ args: {
205008
+ source: "animateFromSequence",
205009
+ property: prop,
205010
+ component: target.componentType
205011
+ }
205012
+ })
205013
+ );
204784
205014
  } else {
204785
- let message = `Invalid target for \`<animateFromSequence>\`: cannot find a state variable named "value" on a \`<${target.componentType}>\`.`;
204786
- diagnostics2.push({
204787
- message,
204788
- type: "warning"
204789
- });
205015
+ diagnostics2.push(
205016
+ codedDiagnostic({
205017
+ type: "warning",
205018
+ code: "doenet-w0044",
205019
+ args: {
205020
+ source: "animateFromSequence",
205021
+ property: "value",
205022
+ component: target.componentType
205023
+ }
205024
+ })
205025
+ );
204790
205026
  }
204791
205027
  }
204792
205028
  }
@@ -208482,11 +208718,14 @@ class Image extends BlockComponent {
208482
208718
  shortDescription = shortDescriptionChild.stateValues.text.trim();
208483
208719
  }
208484
208720
  if (shortDescription === "" && !dependencyValues.decorative) {
208485
- diagnostics2.push({
208486
- type: "accessibility",
208487
- level: 1,
208488
- message: "For accessibility, `<image>` must either have a short description or be specified as decorative."
208489
- });
208721
+ diagnostics2.push(
208722
+ codedDiagnostic({
208723
+ type: "accessibility",
208724
+ level: 1,
208725
+ code: "doenet-a0001",
208726
+ args: { component: "image" }
208727
+ })
208728
+ );
208490
208729
  }
208491
208730
  return {
208492
208731
  setValue: { shortDescription },
@@ -209092,11 +209331,13 @@ class Video extends BlockComponent {
209092
209331
  shortDescription = shortDescriptionChild.stateValues.text.trim();
209093
209332
  }
209094
209333
  if (shortDescription === "") {
209095
- diagnostics2.push({
209096
- type: "accessibility",
209097
- level: 1,
209098
- message: "For accessibility, `<video>` must have a short description."
209099
- });
209334
+ diagnostics2.push(
209335
+ codedDiagnostic({
209336
+ type: "accessibility",
209337
+ level: 1,
209338
+ code: "doenet-a0002"
209339
+ })
209340
+ );
209100
209341
  }
209101
209342
  return {
209102
209343
  setValue: { shortDescription },
@@ -215857,16 +216098,13 @@ class FunctionIterates extends InlineComponent {
215857
216098
  return { setValue: { numDimensions: 0 } };
215858
216099
  } else if (dependencyValues.functionAttr.stateValues.numInputs !== dependencyValues.functionAttr.stateValues.numOutputs) {
215859
216100
  let numInputs = dependencyValues.functionAttr.stateValues.numInputs;
215860
- let numInputsPhrase = numInputs.toString() + (numInputs === 1 ? " input" : " inputs");
215861
216101
  let numOutputs = dependencyValues.functionAttr.stateValues.numOutputs;
215862
- let numOutputsPhrase = numOutputs.toString() + (numOutputs === 1 ? " output" : " outputs");
215863
- let warning = {
216102
+ let warning = codedDiagnostic({
215864
216103
  type: "warning",
215865
- message: `Function iterates are possible only if the number of inputs of the function is equal to the number of outputs. This function has ${numInputsPhrase} and ${numOutputsPhrase}.`
215866
- };
215867
- if (dependencyValues.functionAttr.position) {
215868
- warning.position = dependencyValues.functionAttr.position;
215869
- }
216104
+ code: "doenet-w0056",
216105
+ args: { inputs: numInputs, outputs: numOutputs },
216106
+ position: dependencyValues.functionAttr.position || void 0
216107
+ });
215870
216108
  return {
215871
216109
  setValue: { numDimensions: 0 },
215872
216110
  sendDiagnostics: [warning]
@@ -216505,19 +216743,25 @@ class Sort extends CompositeComponent {
216505
216743
  type = componentAttributes.type.value;
216506
216744
  } else {
216507
216745
  if (matchedChildren.some((child) => typeof child === "string")) {
216508
- diagnostics2.push({
216509
- type: "warning",
216510
- message: `For \`<sort>\` to work with string children, a \`type\` attribute must be specified.`
216511
- });
216746
+ diagnostics2.push(
216747
+ codedDiagnostic({
216748
+ type: "warning",
216749
+ code: "doenet-w0013",
216750
+ args: { component: "sort" }
216751
+ })
216752
+ );
216512
216753
  }
216513
216754
  return { success: false, diagnostics: diagnostics2 };
216514
216755
  }
216515
216756
  if (!["math", "text", "number", "boolean"].includes(type)) {
216516
216757
  console.warn(`Invalid type ${type}`);
216517
- diagnostics2.push({
216518
- type: "warning",
216519
- message: `Invalid type ${type} for sort component. Must be one of math, text, number, or boolean. Defaulting to math.`
216520
- });
216758
+ diagnostics2.push(
216759
+ codedDiagnostic({
216760
+ type: "warning",
216761
+ code: "doenet-w0014",
216762
+ args: { type, component: "sort" }
216763
+ })
216764
+ );
216521
216765
  type = "math";
216522
216766
  }
216523
216767
  let groupIntoComponentTypesSeparatedBySpaces = returnGroupIntoComponentTypeSeparatedBySpacesOutsideParens({
@@ -216581,10 +216825,13 @@ class Sort extends CompositeComponent {
216581
216825
  const diagnostics2 = [];
216582
216826
  for (let child of dependencyValues.children) {
216583
216827
  if (typeof child === "string") {
216584
- diagnostics2.push({
216585
- type: "warning",
216586
- message: `String "${child}" is not a valid component to sort. Ignoring.`
216587
- });
216828
+ diagnostics2.push(
216829
+ codedDiagnostic({
216830
+ type: "warning",
216831
+ code: "doenet-w0015",
216832
+ args: { value: child, component: "sort" }
216833
+ })
216834
+ );
216588
216835
  continue;
216589
216836
  }
216590
216837
  if (child.stateValues.componentIndicesInList) {
@@ -216915,19 +217162,25 @@ class Shuffle extends CompositeComponent {
216915
217162
  type = componentAttributes.type.value;
216916
217163
  } else {
216917
217164
  if (matchedChildren.some((child) => typeof child === "string")) {
216918
- diagnostics2.push({
216919
- type: "warning",
216920
- message: `For \`<shuffle>\` to work with string children, a \`type\` attribute must be specified.`
216921
- });
217165
+ diagnostics2.push(
217166
+ codedDiagnostic({
217167
+ type: "warning",
217168
+ code: "doenet-w0013",
217169
+ args: { component: "shuffle" }
217170
+ })
217171
+ );
216922
217172
  }
216923
217173
  return { success: false, diagnostics: diagnostics2 };
216924
217174
  }
216925
217175
  if (!["math", "text", "number", "boolean"].includes(type)) {
216926
217176
  console.warn(`Invalid type ${type}`);
216927
- diagnostics2.push({
216928
- type: "warning",
216929
- message: `Invalid type ${type} for shuffle component. Must be one of math, text, number, or boolean. Defaulting to math.`
216930
- });
217177
+ diagnostics2.push(
217178
+ codedDiagnostic({
217179
+ type: "warning",
217180
+ code: "doenet-w0014",
217181
+ args: { type, component: "shuffle" }
217182
+ })
217183
+ );
216931
217184
  type = "math";
216932
217185
  }
216933
217186
  let groupIntoComponentTypesSeparatedBySpaces = returnGroupIntoComponentTypeSeparatedBySpacesOutsideParens({
@@ -216981,10 +217234,13 @@ class Shuffle extends CompositeComponent {
216981
217234
  const diagnostics2 = [];
216982
217235
  for (let child of dependencyValues.children) {
216983
217236
  if (typeof child === "string") {
216984
- diagnostics2.push({
216985
- type: "warning",
216986
- message: `String "${child}" is not a valid component to shuffle. Ignoring.`
216987
- });
217237
+ diagnostics2.push(
217238
+ codedDiagnostic({
217239
+ type: "warning",
217240
+ code: "doenet-w0015",
217241
+ args: { value: child, component: "shuffle" }
217242
+ })
217243
+ );
216988
217244
  }
216989
217245
  if (child.stateValues?.componentIndicesInList) {
216990
217246
  originalComponentIndices.push(
@@ -217031,10 +217287,12 @@ class Shuffle extends CompositeComponent {
217031
217287
  let desiredComponentOrder = dependencyValues.variants?.desiredVariant?.indices;
217032
217288
  if (desiredComponentOrder !== void 0) {
217033
217289
  if (desiredComponentOrder.length !== numComponents) {
217034
- diagnostics2.push({
217035
- message: "Ignoring indices specified for shuffle as number of indices doesn't match number of components.",
217036
- type: "info"
217037
- });
217290
+ diagnostics2.push(
217291
+ codedDiagnostic({
217292
+ type: "info",
217293
+ code: "doenet-i0006"
217294
+ })
217295
+ );
217038
217296
  } else {
217039
217297
  desiredComponentOrder = desiredComponentOrder.map(Number);
217040
217298
  if (!desiredComponentOrder.every(Number.isInteger)) {
@@ -217045,10 +217303,13 @@ class Shuffle extends CompositeComponent {
217045
217303
  if (!desiredComponentOrder.every(
217046
217304
  (x2) => x2 >= 1 && x2 <= numComponents
217047
217305
  )) {
217048
- diagnostics2.push({
217049
- message: "Ignoring indices specified for shuffle as some indices out of range.",
217050
- type: "info"
217051
- });
217306
+ diagnostics2.push(
217307
+ codedDiagnostic({
217308
+ type: "info",
217309
+ code: "doenet-i0007",
217310
+ args: { component: "shuffle" }
217311
+ })
217312
+ );
217052
217313
  } else {
217053
217314
  return {
217054
217315
  setValue: {
@@ -217539,8 +217800,13 @@ class SolveEquations extends InlineComponent {
217539
217800
  try {
217540
217801
  f_base = formula.f();
217541
217802
  } catch (e32) {
217542
- let message = "Cannot solve equation as could not evaluate equation: " + expression.toString();
217543
- let diagnostics2 = [{ message, type: "warning" }];
217803
+ let diagnostics2 = [
217804
+ codedDiagnostic({
217805
+ type: "warning",
217806
+ code: "doenet-w0057",
217807
+ args: { equation: expression.toString() }
217808
+ })
217809
+ ];
217544
217810
  return {
217545
217811
  setValue: { allSolutions: [] },
217546
217812
  sendDiagnostics: diagnostics2
@@ -223177,10 +223443,10 @@ class EigenDecomposition extends BaseComponent {
223177
223443
  "Could nt calculate eigenvalues of matrix",
223178
223444
  e32
223179
223445
  );
223180
- let warning = {
223181
- message: "Could not calculate eigenvalues of matrix",
223182
- type: "warning"
223183
- };
223446
+ let warning = codedDiagnostic({
223447
+ type: "warning",
223448
+ code: "doenet-w0059"
223449
+ });
223184
223450
  return {
223185
223451
  setValue: { decomposition: null, numEigenvectors: 0 },
223186
223452
  sendDiagnostics: [warning]
@@ -225360,10 +225626,12 @@ class PretzelArranger extends CompositeComponent {
225360
225626
  let desiredProblemOrder = dependencyValues.variants?.desiredVariant?.indices;
225361
225627
  if (desiredProblemOrder !== void 0) {
225362
225628
  if (desiredProblemOrder.length !== numProblems) {
225363
- diagnostics2.push({
225364
- message: "Ignoring indices specified for problem as number of indices doesn't match number of problem children.",
225365
- type: "info"
225366
- });
225629
+ diagnostics2.push(
225630
+ codedDiagnostic({
225631
+ type: "info",
225632
+ code: "doenet-i0005"
225633
+ })
225634
+ );
225367
225635
  } else {
225368
225636
  desiredProblemOrder = desiredProblemOrder.map(Number);
225369
225637
  if (!desiredProblemOrder.every(Number.isInteger)) {
@@ -225374,20 +225642,27 @@ class PretzelArranger extends CompositeComponent {
225374
225642
  if (!desiredProblemOrder.every(
225375
225643
  (x2) => x2 >= 1 && x2 <= numProblems
225376
225644
  )) {
225377
- diagnostics2.push({
225378
- message: "Ignoring indices specified for pretzel as some indices out of range.",
225379
- type: "info"
225380
- });
225645
+ diagnostics2.push(
225646
+ codedDiagnostic({
225647
+ type: "info",
225648
+ code: "doenet-i0007",
225649
+ args: { component: "pretzel" }
225650
+ })
225651
+ );
225381
225652
  } else if (new Set(desiredProblemOrder).size !== numProblems) {
225382
- diagnostics2.push({
225383
- message: "Ignoring indices specified for pretzel as some indices are repeated.",
225384
- type: "info"
225385
- });
225653
+ diagnostics2.push(
225654
+ codedDiagnostic({
225655
+ type: "info",
225656
+ code: "doenet-i0008"
225657
+ })
225658
+ );
225386
225659
  } else if (mode === "circuit" && numProblems > 0 && desiredProblemOrder[0] !== 1) {
225387
- diagnostics2.push({
225388
- message: "Ignoring indices specified for pretzel in circuit mode as the first index must be 1.",
225389
- type: "info"
225390
- });
225660
+ diagnostics2.push(
225661
+ codedDiagnostic({
225662
+ type: "info",
225663
+ code: "doenet-i0009"
225664
+ })
225665
+ );
225391
225666
  } else {
225392
225667
  return {
225393
225668
  setValue: {
@@ -226416,11 +226691,14 @@ class ShortDescription extends TextOrInline {
226416
226691
  }
226417
226692
  const diagnostics2 = [];
226418
226693
  if (foundMathType) {
226419
- diagnostics2.push({
226420
- type: "accessibility",
226421
- level: 2,
226422
- message: `Short descriptions should not contain math components such as \`<${foundMathType}>\`. Spell out any math with words.`
226423
- });
226694
+ diagnostics2.push(
226695
+ codedDiagnostic({
226696
+ type: "accessibility",
226697
+ level: 2,
226698
+ code: "doenet-a0005",
226699
+ args: { component: foundMathType }
226700
+ })
226701
+ );
226424
226702
  }
226425
226703
  return { setValue: { value }, sendDiagnostics: diagnostics2 };
226426
226704
  }
@@ -229764,10 +230042,13 @@ class VariableNameList extends MathList {
229764
230042
  let variable = dependencyValuesByKey[arrayKey].math;
229765
230043
  let validVariable = isValidVariable(variable);
229766
230044
  if (!validVariable) {
229767
- diagnostics2.push({
229768
- message: "Invalid value of a variable: `" + variable.toString() + "`",
229769
- type: "warning"
229770
- });
230045
+ diagnostics2.push(
230046
+ codedDiagnostic({
230047
+ type: "warning",
230048
+ code: "doenet-w0017",
230049
+ args: { value: variable.toString() }
230050
+ })
230051
+ );
229771
230052
  validVariable = false;
229772
230053
  }
229773
230054
  variables2[arrayKey] = variable;
@@ -229812,10 +230093,15 @@ class Variable extends MathComponent {
229812
230093
  dependencyValues.valuePreValidate
229813
230094
  );
229814
230095
  if (!validVariable) {
229815
- diagnostics2.push({
229816
- message: "Invalid value of a variable: `" + dependencyValues.valuePreValidate.toString() + "`",
229817
- type: "warning"
229818
- });
230096
+ diagnostics2.push(
230097
+ codedDiagnostic({
230098
+ type: "warning",
230099
+ code: "doenet-w0017",
230100
+ args: {
230101
+ value: dependencyValues.valuePreValidate.toString()
230102
+ }
230103
+ })
230104
+ );
229819
230105
  }
229820
230106
  return {
229821
230107
  setValue: {
@@ -232849,4 +233135,4 @@ export {
232849
233135
  getDefaultExportFromCjs as g,
232850
233136
  updateSyntaxFromV06toV07 as u
232851
233137
  };
232852
- //# sourceMappingURL=index-NJbOIT2j.js.map
233138
+ //# sourceMappingURL=index-CdNFDkf5.js.map