@horizon36596/zenith-core 0.1.1
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.
- package/LICENSE +21 -0
- package/NOTICE +18 -0
- package/README.md +16 -0
- package/dist/canonicalize.d.ts +25 -0
- package/dist/canonicalize.d.ts.map +1 -0
- package/dist/canonicalize.js +199 -0
- package/dist/canonicalize.js.map +1 -0
- package/dist/check.d.ts +26 -0
- package/dist/check.d.ts.map +1 -0
- package/dist/check.js +231 -0
- package/dist/check.js.map +1 -0
- package/dist/checks/heading.d.ts +17 -0
- package/dist/checks/heading.d.ts.map +1 -0
- package/dist/checks/heading.js +78 -0
- package/dist/checks/heading.js.map +1 -0
- package/dist/checks/intake.d.ts +28 -0
- package/dist/checks/intake.d.ts.map +1 -0
- package/dist/checks/intake.js +131 -0
- package/dist/checks/intake.js.map +1 -0
- package/dist/checks/motion.d.ts +28 -0
- package/dist/checks/motion.d.ts.map +1 -0
- package/dist/checks/motion.js +252 -0
- package/dist/checks/motion.js.map +1 -0
- package/dist/checks/schedule.d.ts +29 -0
- package/dist/checks/schedule.d.ts.map +1 -0
- package/dist/checks/schedule.js +166 -0
- package/dist/checks/schedule.js.map +1 -0
- package/dist/checks/season.d.ts +6 -0
- package/dist/checks/season.d.ts.map +1 -0
- package/dist/checks/season.js +126 -0
- package/dist/checks/season.js.map +1 -0
- package/dist/continuity.d.ts +38 -0
- package/dist/continuity.d.ts.map +1 -0
- package/dist/continuity.js +69 -0
- package/dist/continuity.js.map +1 -0
- package/dist/diff.d.ts +37 -0
- package/dist/diff.d.ts.map +1 -0
- package/dist/diff.js +258 -0
- package/dist/diff.js.map +1 -0
- package/dist/edit/command.d.ts +4 -0
- package/dist/edit/command.d.ts.map +1 -0
- package/dist/edit/command.js +16 -0
- package/dist/edit/command.js.map +1 -0
- package/dist/edit/errors.d.ts +9 -0
- package/dist/edit/errors.d.ts.map +1 -0
- package/dist/edit/errors.js +12 -0
- package/dist/edit/errors.js.map +1 -0
- package/dist/edit/fields.d.ts +40 -0
- package/dist/edit/fields.d.ts.map +1 -0
- package/dist/edit/fields.js +150 -0
- package/dist/edit/fields.js.map +1 -0
- package/dist/edit/finish.d.ts +15 -0
- package/dist/edit/finish.d.ts.map +1 -0
- package/dist/edit/finish.js +36 -0
- package/dist/edit/finish.js.map +1 -0
- package/dist/edit/groups.d.ts +66 -0
- package/dist/edit/groups.d.ts.map +1 -0
- package/dist/edit/groups.js +277 -0
- package/dist/edit/groups.js.map +1 -0
- package/dist/edit/ids.d.ts +39 -0
- package/dist/edit/ids.d.ts.map +1 -0
- package/dist/edit/ids.js +76 -0
- package/dist/edit/ids.js.map +1 -0
- package/dist/edit/index.d.ts +22 -0
- package/dist/edit/index.d.ts.map +1 -0
- package/dist/edit/index.js +22 -0
- package/dist/edit/index.js.map +1 -0
- package/dist/edit/meta.d.ts +15 -0
- package/dist/edit/meta.d.ts.map +1 -0
- package/dist/edit/meta.js +13 -0
- package/dist/edit/meta.js.map +1 -0
- package/dist/edit/path.d.ts +36 -0
- package/dist/edit/path.d.ts.map +1 -0
- package/dist/edit/path.js +135 -0
- package/dist/edit/path.js.map +1 -0
- package/dist/edit/steps.d.ts +53 -0
- package/dist/edit/steps.d.ts.map +1 -0
- package/dist/edit/steps.js +0 -0
- package/dist/edit/steps.js.map +1 -0
- package/dist/edit/template.d.ts +18 -0
- package/dist/edit/template.d.ts.map +1 -0
- package/dist/edit/template.js +30 -0
- package/dist/edit/template.js.map +1 -0
- package/dist/edit/timing.d.ts +11 -0
- package/dist/edit/timing.d.ts.map +1 -0
- package/dist/edit/timing.js +23 -0
- package/dist/edit/timing.js.map +1 -0
- package/dist/edit/tree.d.ts +32 -0
- package/dist/edit/tree.d.ts.map +1 -0
- package/dist/edit/tree.js +90 -0
- package/dist/edit/tree.js.map +1 -0
- package/dist/estimate.d.ts +48 -0
- package/dist/estimate.d.ts.map +1 -0
- package/dist/estimate.js +443 -0
- package/dist/estimate.js.map +1 -0
- package/dist/findingHelp.d.ts +18 -0
- package/dist/findingHelp.d.ts.map +1 -0
- package/dist/findingHelp.js +114 -0
- package/dist/findingHelp.js.map +1 -0
- package/dist/fix.d.ts +21 -0
- package/dist/fix.d.ts.map +1 -0
- package/dist/fix.js +180 -0
- package/dist/fix.js.map +1 -0
- package/dist/footprint.d.ts +33 -0
- package/dist/footprint.d.ts.map +1 -0
- package/dist/footprint.js +71 -0
- package/dist/footprint.js.map +1 -0
- package/dist/geometry/angle.d.ts +13 -0
- package/dist/geometry/angle.d.ts.map +1 -0
- package/dist/geometry/angle.js +21 -0
- package/dist/geometry/angle.js.map +1 -0
- package/dist/geometry/curve.d.ts +24 -0
- package/dist/geometry/curve.d.ts.map +1 -0
- package/dist/geometry/curve.js +78 -0
- package/dist/geometry/curve.js.map +1 -0
- package/dist/geometry/path.d.ts +29 -0
- package/dist/geometry/path.d.ts.map +1 -0
- package/dist/geometry/path.js +61 -0
- package/dist/geometry/path.js.map +1 -0
- package/dist/geometry/quadrature.d.ts +13 -0
- package/dist/geometry/quadrature.d.ts.map +1 -0
- package/dist/geometry/quadrature.js +57 -0
- package/dist/geometry/quadrature.js.map +1 -0
- package/dist/geometry/sat.d.ts +40 -0
- package/dist/geometry/sat.d.ts.map +1 -0
- package/dist/geometry/sat.js +86 -0
- package/dist/geometry/sat.js.map +1 -0
- package/dist/geometry/vec.d.ts +27 -0
- package/dist/geometry/vec.d.ts.map +1 -0
- package/dist/geometry/vec.js +30 -0
- package/dist/geometry/vec.js.map +1 -0
- package/dist/heading.d.ts +77 -0
- package/dist/heading.d.ts.map +1 -0
- package/dist/heading.js +164 -0
- package/dist/heading.js.map +1 -0
- package/dist/headingRanges.d.ts +48 -0
- package/dist/headingRanges.d.ts.map +1 -0
- package/dist/headingRanges.js +132 -0
- package/dist/headingRanges.js.map +1 -0
- package/dist/index.d.ts +41 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +41 -0
- package/dist/index.js.map +1 -0
- package/dist/kinematics.d.ts +63 -0
- package/dist/kinematics.d.ts.map +1 -0
- package/dist/kinematics.js +71 -0
- package/dist/kinematics.js.map +1 -0
- package/dist/ledger.d.ts +49 -0
- package/dist/ledger.d.ts.map +1 -0
- package/dist/ledger.js +136 -0
- package/dist/ledger.js.map +1 -0
- package/dist/load.d.ts +12 -0
- package/dist/load.d.ts.map +1 -0
- package/dist/load.js +12 -0
- package/dist/load.js.map +1 -0
- package/dist/mirror.d.ts +81 -0
- package/dist/mirror.d.ts.map +1 -0
- package/dist/mirror.js +282 -0
- package/dist/mirror.js.map +1 -0
- package/dist/plan.d.ts +29 -0
- package/dist/plan.d.ts.map +1 -0
- package/dist/plan.js +159 -0
- package/dist/plan.js.map +1 -0
- package/dist/prBody.d.ts +24 -0
- package/dist/prBody.d.ts.map +1 -0
- package/dist/prBody.js +112 -0
- package/dist/prBody.js.map +1 -0
- package/dist/provenance.d.ts +21 -0
- package/dist/provenance.d.ts.map +1 -0
- package/dist/provenance.js +46 -0
- package/dist/provenance.js.map +1 -0
- package/dist/render.d.ts +18 -0
- package/dist/render.d.ts.map +1 -0
- package/dist/render.js +464 -0
- package/dist/render.js.map +1 -0
- package/dist/resolve.d.ts +39 -0
- package/dist/resolve.d.ts.map +1 -0
- package/dist/resolve.js +172 -0
- package/dist/resolve.js.map +1 -0
- package/dist/season.d.ts +65 -0
- package/dist/season.d.ts.map +1 -0
- package/dist/season.js +16 -0
- package/dist/season.js.map +1 -0
- package/dist/sim/commands.d.ts +97 -0
- package/dist/sim/commands.d.ts.map +1 -0
- package/dist/sim/commands.js +185 -0
- package/dist/sim/commands.js.map +1 -0
- package/dist/sim/curves.d.ts +37 -0
- package/dist/sim/curves.d.ts.map +1 -0
- package/dist/sim/curves.js +187 -0
- package/dist/sim/curves.js.map +1 -0
- package/dist/sim/follower.d.ts +124 -0
- package/dist/sim/follower.d.ts.map +1 -0
- package/dist/sim/follower.js +472 -0
- package/dist/sim/follower.js.map +1 -0
- package/dist/sim/ideal.d.ts +103 -0
- package/dist/sim/ideal.d.ts.map +1 -0
- package/dist/sim/ideal.js +393 -0
- package/dist/sim/ideal.js.map +1 -0
- package/dist/sim/index.d.ts +11 -0
- package/dist/sim/index.d.ts.map +1 -0
- package/dist/sim/index.js +10 -0
- package/dist/sim/index.js.map +1 -0
- package/dist/sim/params.d.ts +91 -0
- package/dist/sim/params.d.ts.map +1 -0
- package/dist/sim/params.js +195 -0
- package/dist/sim/params.js.map +1 -0
- package/dist/sim/pedroPath.d.ts +41 -0
- package/dist/sim/pedroPath.d.ts.map +1 -0
- package/dist/sim/pedroPath.js +191 -0
- package/dist/sim/pedroPath.js.map +1 -0
- package/dist/sim/plant.d.ts +59 -0
- package/dist/sim/plant.d.ts.map +1 -0
- package/dist/sim/plant.js +128 -0
- package/dist/sim/plant.js.map +1 -0
- package/dist/sim/residuals.d.ts +36 -0
- package/dist/sim/residuals.d.ts.map +1 -0
- package/dist/sim/residuals.js +86 -0
- package/dist/sim/residuals.js.map +1 -0
- package/dist/sim/simulate.d.ts +27 -0
- package/dist/sim/simulate.d.ts.map +1 -0
- package/dist/sim/simulate.js +924 -0
- package/dist/sim/simulate.js.map +1 -0
- package/dist/sim/types.d.ts +209 -0
- package/dist/sim/types.d.ts.map +1 -0
- package/dist/sim/types.js +2 -0
- package/dist/sim/types.js.map +1 -0
- package/dist/tokens.d.ts +93 -0
- package/dist/tokens.d.ts.map +1 -0
- package/dist/tokens.js +93 -0
- package/dist/tokens.js.map +1 -0
- package/dist/trace.d.ts +89 -0
- package/dist/trace.d.ts.map +1 -0
- package/dist/trace.js +187 -0
- package/dist/trace.js.map +1 -0
- package/dist/types.d.ts +219 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/dist/unimplemented.d.ts +8 -0
- package/dist/unimplemented.d.ts.map +1 -0
- package/dist/unimplemented.js +11 -0
- package/dist/unimplemented.js.map +1 -0
- package/package.json +59 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Horizon (FTC 36596)
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/NOTICE
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
Zenith
|
|
2
|
+
Copyright (c) 2026 Horizon (FTC 36596)
|
|
3
|
+
|
|
4
|
+
Zenith is licensed under the MIT License; see LICENSE.
|
|
5
|
+
|
|
6
|
+
Third-party assets
|
|
7
|
+
|
|
8
|
+
- BIOBUZZ field images (apps/web/public/fields/biobuzz/*.webp) by Team Juice 16236, from the r/FTC
|
|
9
|
+
post "BIOBUZZ custom field images (MeepMeep compatible)". Used with the credit the author asks for.
|
|
10
|
+
|
|
11
|
+
Bundled fonts
|
|
12
|
+
|
|
13
|
+
The following fonts are bundled in apps/web/public/fonts/. Each is licensed under the SIL Open Font
|
|
14
|
+
License, Version 1.1. The full licence text ships next to each font file.
|
|
15
|
+
|
|
16
|
+
- Jost, licensed under the SIL Open Font License 1.1 (jost-OFL.txt).
|
|
17
|
+
- IBM Plex Sans, licensed under the SIL Open Font License 1.1 (ibm-plex-sans-OFL.txt).
|
|
18
|
+
- JetBrains Mono, licensed under the SIL Open Font License 1.1 (jetbrains-mono-OFL.txt).
|
package/README.md
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# @horizon36596/zenith-core
|
|
2
|
+
|
|
3
|
+
The planning core of [Zenith](https://libraries.horizon36596.org/zenith/), the FTC autonomous planner
|
|
4
|
+
by Horizon (FTC 36596). It turns an auto file into a plan and answers the questions about it: path
|
|
5
|
+
geometry and heading modes, robot footprints, the feasibility checks and their findings, the time
|
|
6
|
+
estimate, the structural edits an editor or agent makes, the canonical file form and the SVG render.
|
|
7
|
+
|
|
8
|
+
```
|
|
9
|
+
npm install @horizon36596/zenith-core
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
The package is pure: no DOM, no clock, no randomness and no Node APIs. The editor, the `zenith` CLI
|
|
13
|
+
and the MCP server all use it, so they give the same answer for the same files.
|
|
14
|
+
|
|
15
|
+
Most projects want [`@horizon36596/zenith-cli`](https://www.npmjs.com/package/@horizon36596/zenith-cli)
|
|
16
|
+
instead. Documentation: https://libraries.horizon36596.org/zenith/. Licence: MIT.
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
import { type Kind } from "@horizon36596/zenith-schema";
|
|
2
|
+
/**
|
|
3
|
+
* Canonical form (site/docs/file-format.md): UTF-8, LF, two-space indent, object keys in schema
|
|
4
|
+
* declaration order (not alphabetical), numbers rounded to 3 decimals for inches, 4 for radians and
|
|
5
|
+
* 3 for seconds (and so for in/s and in/s²) by the key that names the unit, trailing newline. A file round-trips byte-identically through load and save, which
|
|
6
|
+
* is what makes a git diff of an auto readable.
|
|
7
|
+
*
|
|
8
|
+
* The key order comes from the zod schemas themselves, so the schema is the single definition of
|
|
9
|
+
* the order and the two cannot drift apart.
|
|
10
|
+
*/
|
|
11
|
+
export declare function canonicalize(kind: Kind, doc: unknown): string;
|
|
12
|
+
/**
|
|
13
|
+
* Digits after the point for a key, by the unit its name declares, or null for a key that names no
|
|
14
|
+
* unit and is written exactly as given.
|
|
15
|
+
*
|
|
16
|
+
* Only the key that names the unit is rounded. A number inside an object under such a key — the
|
|
17
|
+
* `value` of `maxForwardVelInPerS: { value, provenance }`, the `rapid` of `cadenceS` — names no
|
|
18
|
+
* unit of its own and keeps its full precision: inheriting the parent's unit rounded a MEASURED
|
|
19
|
+
* 72.3456 to 72.346 while the `…InPerS2` values beside it kept every digit. An array's elements do
|
|
20
|
+
* take the unit of the key holding the array, because an array has no keys of its own to name one.
|
|
21
|
+
*/
|
|
22
|
+
export declare function digitsForKey(key: string): number | null;
|
|
23
|
+
/** Rounds to `digits` decimals, without -0 and without exponent notation for our magnitudes. */
|
|
24
|
+
export declare function formatNumber(value: number, digits: number | null): string;
|
|
25
|
+
//# sourceMappingURL=canonicalize.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonicalize.d.ts","sourceRoot":"","sources":["../src/canonicalize.ts"],"names":[],"mappings":"AAAA,OAAO,EAA+D,KAAK,IAAI,EAAE,MAAM,6BAA6B,CAAC;AAGrH;;;;;;;;GAQG;AACH,wBAAgB,YAAY,CAAC,IAAI,EAAE,IAAI,EAAE,GAAG,EAAE,OAAO,GAAG,MAAM,CAE7D;AAsBD;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAOvD;AAED,gGAAgG;AAChG,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAKzE"}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { FORMAT_VERSIONS, migrate, schemaByKind, withCurrentSchemaId } from "@horizon36596/zenith-schema";
|
|
2
|
+
import { z } from "zod";
|
|
3
|
+
/**
|
|
4
|
+
* Canonical form (site/docs/file-format.md): UTF-8, LF, two-space indent, object keys in schema
|
|
5
|
+
* declaration order (not alphabetical), numbers rounded to 3 decimals for inches, 4 for radians and
|
|
6
|
+
* 3 for seconds (and so for in/s and in/s²) by the key that names the unit, trailing newline. A file round-trips byte-identically through load and save, which
|
|
7
|
+
* is what makes a git diff of an auto readable.
|
|
8
|
+
*
|
|
9
|
+
* The key order comes from the zod schemas themselves, so the schema is the single definition of
|
|
10
|
+
* the order and the two cannot drift apart.
|
|
11
|
+
*/
|
|
12
|
+
export function canonicalize(kind, doc) {
|
|
13
|
+
return `${write(atCurrentVersion(kind, doc), schemaByKind[kind], null, "")}\n`;
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Every writer writes the current format version (site/docs/file-format.md, Versioning), so a
|
|
17
|
+
* document handed over at an older version is migrated first. One that cannot be migrated is
|
|
18
|
+
* written as it is: canonical form is about bytes, and refusing the file is the loader's job. A
|
|
19
|
+
* legacy `$schema` alias is always written as the current id (Schema ids, same document).
|
|
20
|
+
*/
|
|
21
|
+
function atCurrentVersion(kind, input) {
|
|
22
|
+
const doc = withCurrentSchemaId(kind, input);
|
|
23
|
+
if (!isRecord(doc))
|
|
24
|
+
return doc;
|
|
25
|
+
const version = doc["formatVersion"];
|
|
26
|
+
if (typeof version !== "number" || version >= FORMAT_VERSIONS[kind])
|
|
27
|
+
return doc;
|
|
28
|
+
try {
|
|
29
|
+
return migrate(doc, kind).data;
|
|
30
|
+
}
|
|
31
|
+
catch {
|
|
32
|
+
return doc;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
const INDENT = " ";
|
|
36
|
+
/**
|
|
37
|
+
* Digits after the point for a key, by the unit its name declares, or null for a key that names no
|
|
38
|
+
* unit and is written exactly as given.
|
|
39
|
+
*
|
|
40
|
+
* Only the key that names the unit is rounded. A number inside an object under such a key — the
|
|
41
|
+
* `value` of `maxForwardVelInPerS: { value, provenance }`, the `rapid` of `cadenceS` — names no
|
|
42
|
+
* unit of its own and keeps its full precision: inheriting the parent's unit rounded a MEASURED
|
|
43
|
+
* 72.3456 to 72.346 while the `…InPerS2` values beside it kept every digit. An array's elements do
|
|
44
|
+
* take the unit of the key holding the array, because an array has no keys of its own to name one.
|
|
45
|
+
*/
|
|
46
|
+
export function digitsForKey(key) {
|
|
47
|
+
if (key.endsWith("Rad"))
|
|
48
|
+
return 4;
|
|
49
|
+
if (key.endsWith("In"))
|
|
50
|
+
return 3;
|
|
51
|
+
// An acceleration (`accelInPerS2`) is inches per second squared, rounded like a speed.
|
|
52
|
+
if (key.endsWith("S2"))
|
|
53
|
+
return 3;
|
|
54
|
+
if (key.endsWith("S"))
|
|
55
|
+
return 3;
|
|
56
|
+
return null;
|
|
57
|
+
}
|
|
58
|
+
/** Rounds to `digits` decimals, without -0 and without exponent notation for our magnitudes. */
|
|
59
|
+
export function formatNumber(value, digits) {
|
|
60
|
+
if (!Number.isFinite(value))
|
|
61
|
+
throw new Error(`Cannot canonicalize the number ${String(value)}.`);
|
|
62
|
+
if (digits === null)
|
|
63
|
+
return JSON.stringify(value === 0 ? 0 : value);
|
|
64
|
+
const rounded = Number(value.toFixed(digits));
|
|
65
|
+
return JSON.stringify(rounded === 0 ? 0 : rounded);
|
|
66
|
+
}
|
|
67
|
+
const isRecord = (value) => typeof value === "object" && value !== null && !Array.isArray(value);
|
|
68
|
+
/** Peels the wrappers that do not change an object's shape. */
|
|
69
|
+
function unwrap(schema) {
|
|
70
|
+
let current = schema;
|
|
71
|
+
for (let guard = 0; guard < 32 && current !== null; guard += 1) {
|
|
72
|
+
if (current instanceof z.ZodOptional ||
|
|
73
|
+
current instanceof z.ZodNullable ||
|
|
74
|
+
current instanceof z.ZodDefault ||
|
|
75
|
+
current instanceof z.ZodReadonly) {
|
|
76
|
+
current = current._def.innerType;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
if (current instanceof z.ZodEffects) {
|
|
80
|
+
current = current._def.schema;
|
|
81
|
+
continue;
|
|
82
|
+
}
|
|
83
|
+
if (current instanceof z.ZodLazy) {
|
|
84
|
+
current = current._def.getter();
|
|
85
|
+
continue;
|
|
86
|
+
}
|
|
87
|
+
return current;
|
|
88
|
+
}
|
|
89
|
+
return current;
|
|
90
|
+
}
|
|
91
|
+
/** The literal values an object schema pins, so a union option can be matched without parsing. */
|
|
92
|
+
function literalsOf(schema) {
|
|
93
|
+
const literals = new Map();
|
|
94
|
+
for (const [key, value] of Object.entries(schema.shape)) {
|
|
95
|
+
const inner = unwrap(value);
|
|
96
|
+
if (inner instanceof z.ZodLiteral)
|
|
97
|
+
literals.set(key, inner.value);
|
|
98
|
+
}
|
|
99
|
+
return literals;
|
|
100
|
+
}
|
|
101
|
+
/** Picks the union member this value belongs to: by its discriminator first, then by parsing. */
|
|
102
|
+
function resolveSchema(schema, value) {
|
|
103
|
+
const current = unwrap(schema);
|
|
104
|
+
if (current === null)
|
|
105
|
+
return null;
|
|
106
|
+
if (current instanceof z.ZodDiscriminatedUnion) {
|
|
107
|
+
const discriminator = current._def.discriminator;
|
|
108
|
+
if (isRecord(value)) {
|
|
109
|
+
const option = current._def.optionsMap.get(value[discriminator]);
|
|
110
|
+
if (option !== undefined)
|
|
111
|
+
return unwrap(option);
|
|
112
|
+
}
|
|
113
|
+
return pickByParsing(current._def.options, value);
|
|
114
|
+
}
|
|
115
|
+
if (current instanceof z.ZodUnion) {
|
|
116
|
+
const options = current._def.options;
|
|
117
|
+
if (isRecord(value)) {
|
|
118
|
+
for (const option of options) {
|
|
119
|
+
const inner = unwrap(option);
|
|
120
|
+
if (!(inner instanceof z.ZodObject))
|
|
121
|
+
continue;
|
|
122
|
+
const literals = literalsOf(inner);
|
|
123
|
+
if (literals.size === 0)
|
|
124
|
+
continue;
|
|
125
|
+
let matches = true;
|
|
126
|
+
for (const [key, literal] of literals) {
|
|
127
|
+
if (value[key] !== literal)
|
|
128
|
+
matches = false;
|
|
129
|
+
}
|
|
130
|
+
if (matches)
|
|
131
|
+
return inner;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
return pickByParsing(options, value);
|
|
135
|
+
}
|
|
136
|
+
return current;
|
|
137
|
+
}
|
|
138
|
+
function pickByParsing(options, value) {
|
|
139
|
+
for (const option of options) {
|
|
140
|
+
if (option.safeParse(value).success)
|
|
141
|
+
return unwrap(option);
|
|
142
|
+
}
|
|
143
|
+
return null;
|
|
144
|
+
}
|
|
145
|
+
function childSchema(schema, key) {
|
|
146
|
+
const current = unwrap(schema);
|
|
147
|
+
if (current instanceof z.ZodObject) {
|
|
148
|
+
const shape = current.shape;
|
|
149
|
+
return shape[key] ?? null;
|
|
150
|
+
}
|
|
151
|
+
if (current instanceof z.ZodRecord)
|
|
152
|
+
return current._def.valueType;
|
|
153
|
+
return null;
|
|
154
|
+
}
|
|
155
|
+
/** Schema declaration order first, then any key the schema does not name, in insertion order. */
|
|
156
|
+
function orderedKeys(schema, value) {
|
|
157
|
+
const current = unwrap(schema);
|
|
158
|
+
const present = Object.keys(value).filter((key) => value[key] !== undefined);
|
|
159
|
+
if (!(current instanceof z.ZodObject))
|
|
160
|
+
return present;
|
|
161
|
+
const declared = Object.keys(current.shape);
|
|
162
|
+
const known = declared.filter((key) => present.includes(key));
|
|
163
|
+
const extra = present.filter((key) => !declared.includes(key));
|
|
164
|
+
return [...known, ...extra];
|
|
165
|
+
}
|
|
166
|
+
function write(value, schema, unitKey, indent) {
|
|
167
|
+
if (value === null)
|
|
168
|
+
return "null";
|
|
169
|
+
if (typeof value === "boolean")
|
|
170
|
+
return value ? "true" : "false";
|
|
171
|
+
if (typeof value === "string")
|
|
172
|
+
return JSON.stringify(value);
|
|
173
|
+
if (typeof value === "number") {
|
|
174
|
+
return formatNumber(value, unitKey === null ? null : digitsForKey(unitKey));
|
|
175
|
+
}
|
|
176
|
+
const resolved = resolveSchema(schema, value);
|
|
177
|
+
const inner = indent + INDENT;
|
|
178
|
+
if (Array.isArray(value)) {
|
|
179
|
+
if (value.length === 0)
|
|
180
|
+
return "[]";
|
|
181
|
+
const element = resolved instanceof z.ZodArray ? resolved._def.type : null;
|
|
182
|
+
const items = value.map((item) => `${inner}${write(item, element, unitKey, inner)}`);
|
|
183
|
+
return `[\n${items.join(",\n")}\n${indent}]`;
|
|
184
|
+
}
|
|
185
|
+
if (isRecord(value)) {
|
|
186
|
+
const keys = orderedKeys(resolved, value);
|
|
187
|
+
if (keys.length === 0)
|
|
188
|
+
return "{}";
|
|
189
|
+
const lines = keys.map((key) => {
|
|
190
|
+
// A key names its own unit or none at all; the parent's never reaches into an object.
|
|
191
|
+
const childUnit = digitsForKey(key) === null ? null : key;
|
|
192
|
+
const child = write(value[key], childSchema(resolved, key), childUnit, inner);
|
|
193
|
+
return `${inner}${JSON.stringify(key)}: ${child}`;
|
|
194
|
+
});
|
|
195
|
+
return `{\n${lines.join(",\n")}\n${indent}}`;
|
|
196
|
+
}
|
|
197
|
+
throw new Error(`Cannot canonicalize a value of type ${typeof value}.`);
|
|
198
|
+
}
|
|
199
|
+
//# sourceMappingURL=canonicalize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"canonicalize.js","sourceRoot":"","sources":["../src/canonicalize.ts"],"names":[],"mappings":"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"}
|
package/dist/check.d.ts
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { type Field, type Robot } from "@horizon36596/zenith-schema";
|
|
2
|
+
import { type SeasonRules } from "./season.js";
|
|
3
|
+
import type { Estimate, Finding, Plan } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* How far outside the field a footprint corner may sit before PERIMETER fires, in inches.
|
|
6
|
+
*
|
|
7
|
+
* A start pose touching the wall is legal and common, and canonical form rounds headings to four
|
|
8
|
+
* decimals, so a nose-to-the-wall pose is out by a ten-thousandth of an inch by arithmetic alone.
|
|
9
|
+
* This tolerance is far below anything a person can measure and far above that.
|
|
10
|
+
*/
|
|
11
|
+
export declare const PERIMETER_TOLERANCE_IN = 0.05;
|
|
12
|
+
/**
|
|
13
|
+
* Every check of site/docs/checks-and-findings.md.
|
|
14
|
+
*
|
|
15
|
+
* The ones that need no timing (SCHEMA, CONTINUITY, HEADING_MISSING, HEADING, PERIMETER, STRUCTURE,
|
|
16
|
+
* START_ILLEGAL, KEEPOUT, MOUTH_LEADING, SWEEP_SPEED, STATIONARY_MARKER, MOVES_ROBOT, PROVENANCE
|
|
17
|
+
* and the ledger's own) run whatever is passed for `estimate`; STRAFE_FRACTION, TIME_BUDGET and
|
|
18
|
+
* TIMEOUT_TIGHT need it and are skipped when it is null.
|
|
19
|
+
*
|
|
20
|
+
* Pure: the same plan always produces the same findings in the same order, so a golden test and a
|
|
21
|
+
* pull-request body can both rely on it.
|
|
22
|
+
*/
|
|
23
|
+
export declare function check(plan: Plan, estimate: Estimate | null, robot: Robot, field: Field, season?: SeasonRules): Finding[];
|
|
24
|
+
/** True when any finding is an error, which is what `zenith validate` exits non-zero on. */
|
|
25
|
+
export declare const hasErrors: (findings: readonly Finding[]) => boolean;
|
|
26
|
+
//# sourceMappingURL=check.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,KAAK,EAEV,KAAK,KAAK,EAEX,MAAM,6BAA6B,CAAC;AAarC,OAAO,EAAiB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAC9D,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAY,MAAM,YAAY,CAAC;AAEpE;;;;;;GAMG;AACH,eAAO,MAAM,sBAAsB,OAAO,CAAC;AAgB3C;;;;;;;;;;GAUG;AACH,wBAAgB,KAAK,CACnB,IAAI,EAAE,IAAI,EACV,QAAQ,EAAE,QAAQ,GAAG,IAAI,EACzB,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,KAAK,EACZ,MAAM,GAAE,WAA2B,GAClC,OAAO,EAAE,CAgBX;AAuLD,4FAA4F;AAC5F,eAAO,MAAM,SAAS,GAAI,UAAU,SAAS,OAAO,EAAE,KAAG,OACC,CAAC"}
|
package/dist/check.js
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
import {} from "@horizon36596/zenith-schema";
|
|
2
|
+
import { checkHeading } from "./checks/heading.js";
|
|
3
|
+
import { checkMotion } from "./checks/motion.js";
|
|
4
|
+
import { CONTINUITY_TOLERANCE_IN, continuityGaps } from "./continuity.js";
|
|
5
|
+
import { checkSchedule } from "./checks/schedule.js";
|
|
6
|
+
import { checkSeason } from "./checks/season.js";
|
|
7
|
+
import { duplicateIds } from "./edit/ids.js";
|
|
8
|
+
import { fieldBounds } from "./footprint.js";
|
|
9
|
+
import { polygonOutsideBox, polygonOverlapsBox } from "./geometry/sat.js";
|
|
10
|
+
import { robotHeightIn } from "./kinematics.js";
|
|
11
|
+
import { runLedger } from "./ledger.js";
|
|
12
|
+
import { flattenSteps } from "./plan.js";
|
|
13
|
+
import { noSeasonRules } from "./season.js";
|
|
14
|
+
/**
|
|
15
|
+
* How far outside the field a footprint corner may sit before PERIMETER fires, in inches.
|
|
16
|
+
*
|
|
17
|
+
* A start pose touching the wall is legal and common, and canonical form rounds headings to four
|
|
18
|
+
* decimals, so a nose-to-the-wall pose is out by a ten-thousandth of an inch by arithmetic alone.
|
|
19
|
+
* This tolerance is far below anything a person can measure and far above that.
|
|
20
|
+
*/
|
|
21
|
+
export const PERIMETER_TOLERANCE_IN = 0.05;
|
|
22
|
+
const obstacleBox = (obstacle) => ({
|
|
23
|
+
minXIn: obstacle.minXIn,
|
|
24
|
+
maxXIn: obstacle.maxXIn,
|
|
25
|
+
minYIn: obstacle.minYIn,
|
|
26
|
+
maxYIn: obstacle.maxYIn,
|
|
27
|
+
});
|
|
28
|
+
/**
|
|
29
|
+
* The z gate: an obstacle only matters when its underside is lower than the robot is tall. The RED
|
|
30
|
+
* hive's pivot bar starts at 25.5 in, so an 18 in robot drives under it; the hive's base does not.
|
|
31
|
+
*/
|
|
32
|
+
const reachesRobot = (obstacle, robotHeightIn) => obstacle.minZIn < robotHeightIn;
|
|
33
|
+
/**
|
|
34
|
+
* Every check of site/docs/checks-and-findings.md.
|
|
35
|
+
*
|
|
36
|
+
* The ones that need no timing (SCHEMA, CONTINUITY, HEADING_MISSING, HEADING, PERIMETER, STRUCTURE,
|
|
37
|
+
* START_ILLEGAL, KEEPOUT, MOUTH_LEADING, SWEEP_SPEED, STATIONARY_MARKER, MOVES_ROBOT, PROVENANCE
|
|
38
|
+
* and the ledger's own) run whatever is passed for `estimate`; STRAFE_FRACTION, TIME_BUDGET and
|
|
39
|
+
* TIMEOUT_TIGHT need it and are skipped when it is null.
|
|
40
|
+
*
|
|
41
|
+
* Pure: the same plan always produces the same findings in the same order, so a golden test and a
|
|
42
|
+
* pull-request body can both rely on it.
|
|
43
|
+
*/
|
|
44
|
+
export function check(plan, estimate, robot, field, season = noSeasonRules) {
|
|
45
|
+
const findings = [...plan.findings];
|
|
46
|
+
const steps = flattenSteps(plan.steps);
|
|
47
|
+
findings.push(...checkIds(plan));
|
|
48
|
+
findings.push(...checkRegistry(plan, robot));
|
|
49
|
+
findings.push(...checkGroups(steps));
|
|
50
|
+
findings.push(...checkContinuity(plan.steps, plan.startPose));
|
|
51
|
+
findings.push(...checkGeometry(steps, robot, field));
|
|
52
|
+
findings.push(...checkHeading(steps));
|
|
53
|
+
findings.push(...season.startLegal(field, plan.startPose, robot, plan.auto.alliance));
|
|
54
|
+
findings.push(...checkMotion(plan, estimate, robot, field, steps));
|
|
55
|
+
findings.push(...checkSeason(plan, robot, season, runLedger(plan, field, season)));
|
|
56
|
+
findings.push(...checkSchedule(estimate, robot, field, steps));
|
|
57
|
+
return findings;
|
|
58
|
+
}
|
|
59
|
+
/** SCHEMA: a command or condition the robot's registry does not define. */
|
|
60
|
+
function checkRegistry(plan, robot) {
|
|
61
|
+
const findings = [];
|
|
62
|
+
const commands = new Set(robot.commands.map((command) => command.name));
|
|
63
|
+
const conditions = new Set((robot.conditions ?? []).map((condition) => condition.name));
|
|
64
|
+
const wantCommand = (name, stepId, where) => {
|
|
65
|
+
if (!commands.has(name)) {
|
|
66
|
+
findings.push({
|
|
67
|
+
severity: "error",
|
|
68
|
+
stepId,
|
|
69
|
+
code: "SCHEMA",
|
|
70
|
+
message: `${where} names the command ${JSON.stringify(name)}, which robot.json does not register.`,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
};
|
|
74
|
+
const wantCondition = (name, stepId, where) => {
|
|
75
|
+
if (!conditions.has(name)) {
|
|
76
|
+
findings.push({
|
|
77
|
+
severity: "error",
|
|
78
|
+
stepId,
|
|
79
|
+
code: "SCHEMA",
|
|
80
|
+
message: `${where} names the condition ${JSON.stringify(name)}, which robot.json does not register.`,
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
};
|
|
84
|
+
for (const planned of flattenSteps(plan.steps)) {
|
|
85
|
+
const step = planned.step;
|
|
86
|
+
switch (step.kind) {
|
|
87
|
+
case "command":
|
|
88
|
+
wantCommand(step.name, planned.id, "This step");
|
|
89
|
+
break;
|
|
90
|
+
case "path":
|
|
91
|
+
for (const marker of step.markers ?? []) {
|
|
92
|
+
wantCommand(marker.command.name, planned.id, "A marker on this step");
|
|
93
|
+
}
|
|
94
|
+
if (step.endCondition !== undefined) {
|
|
95
|
+
wantCondition(step.endCondition.condition, planned.id, "This step's endCondition");
|
|
96
|
+
}
|
|
97
|
+
break;
|
|
98
|
+
case "wait":
|
|
99
|
+
if (step.until !== undefined)
|
|
100
|
+
wantCondition(step.until, planned.id, "This wait");
|
|
101
|
+
break;
|
|
102
|
+
case "branch":
|
|
103
|
+
wantCondition(step.condition, planned.id, "This branch");
|
|
104
|
+
break;
|
|
105
|
+
default:
|
|
106
|
+
break;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
return findings;
|
|
110
|
+
}
|
|
111
|
+
/**
|
|
112
|
+
* SCHEMA: the same effective id on two steps.
|
|
113
|
+
*
|
|
114
|
+
* Every finding, every one-click fix and every `zenith.edit.*` primitive addresses a step by this
|
|
115
|
+
* id, and all of them take the first match, so a repeated id makes the second step's error
|
|
116
|
+
* indistinguishable from the first's and silently points every edit at the wrong step. The schema
|
|
117
|
+
* cannot express it (an id is optional and a positional one is minted from the index), so it is
|
|
118
|
+
* checked here, over the whole tree.
|
|
119
|
+
*/
|
|
120
|
+
function checkIds(plan) {
|
|
121
|
+
return duplicateIds(plan.auto.steps).map((id) => ({
|
|
122
|
+
severity: "error",
|
|
123
|
+
stepId: id,
|
|
124
|
+
code: "SCHEMA",
|
|
125
|
+
message: `Two steps have the id ${JSON.stringify(id)}; every step is addressed by its id, so it has to name one step.`,
|
|
126
|
+
}));
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* SCHEMA: a `deadline` parallel group whose `deadline` does not name one of its own direct
|
|
130
|
+
* children.
|
|
131
|
+
*
|
|
132
|
+
* Nothing in the file format can express this, so it is checked here: the estimator has no step to
|
|
133
|
+
* time the group by, the generated Java falls back to a different member than the estimate assumed,
|
|
134
|
+
* and the runtime throws at init. Naming a grandchild or a step outside the group is the same
|
|
135
|
+
* mistake as naming nothing.
|
|
136
|
+
*/
|
|
137
|
+
function checkGroups(steps) {
|
|
138
|
+
const findings = [];
|
|
139
|
+
for (const step of steps) {
|
|
140
|
+
if (step.step.kind !== "parallel" || step.step.mode !== "deadline")
|
|
141
|
+
continue;
|
|
142
|
+
const deadline = step.step.deadline;
|
|
143
|
+
const children = step.children ?? [];
|
|
144
|
+
if (deadline !== undefined && children.some((child) => child.id === deadline))
|
|
145
|
+
continue;
|
|
146
|
+
const names = children.map((child) => JSON.stringify(child.id)).join(", ");
|
|
147
|
+
findings.push({
|
|
148
|
+
severity: "error",
|
|
149
|
+
stepId: step.id,
|
|
150
|
+
code: "SCHEMA",
|
|
151
|
+
message: deadline === undefined
|
|
152
|
+
? `This group runs until its deadline step finishes but names no deadline; name one of ${names}.`
|
|
153
|
+
: `This group's deadline names ${JSON.stringify(deadline)}, which is not one of its own steps (${names}).`,
|
|
154
|
+
});
|
|
155
|
+
}
|
|
156
|
+
return findings;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* CONTINUITY: segment endpoints inside the tolerance, and each step starting where the robot was.
|
|
160
|
+
* The walk itself, including how sequences, parallel groups and branches chain, is
|
|
161
|
+
* `continuityGaps`, which the editor's insert-in-the-middle reads as well.
|
|
162
|
+
*/
|
|
163
|
+
function checkContinuity(steps, entry) {
|
|
164
|
+
return continuityGaps(steps, entry).map((gap) => ({
|
|
165
|
+
severity: "error",
|
|
166
|
+
stepId: gap.stepId,
|
|
167
|
+
code: "CONTINUITY",
|
|
168
|
+
message: gap.where === "segment"
|
|
169
|
+
? `Segment ${String((gap.segmentIndex ?? 0) + 1)} starts ${gap.gapIn.toFixed(2)} in from where segment ${String(gap.segmentIndex ?? 0)} ended; the limit is ${String(CONTINUITY_TOLERANCE_IN)} in.`
|
|
170
|
+
: `This step starts ${gap.gapIn.toFixed(2)} in from where the robot was; the limit is ${String(CONTINUITY_TOLERANCE_IN)} in.`,
|
|
171
|
+
geometry: { pointIn: gap.pointIn },
|
|
172
|
+
}));
|
|
173
|
+
}
|
|
174
|
+
/** PERIMETER and STRUCTURE, over every footprint sample of every step. */
|
|
175
|
+
function checkGeometry(steps, robot, field) {
|
|
176
|
+
const findings = [];
|
|
177
|
+
const bounds = fieldBounds(field);
|
|
178
|
+
const heightIn = robotHeightIn(robot);
|
|
179
|
+
const obstacles = (field.obstacles ?? []).filter((obstacle) => (obstacle.solidToRobot ?? true) && reachesRobot(obstacle, heightIn));
|
|
180
|
+
for (const step of steps) {
|
|
181
|
+
if (step.samples.length === 0)
|
|
182
|
+
continue;
|
|
183
|
+
let worstOutside = { worstIn: 0, t: 0, pointIn: { xIn: 0, yIn: 0 } };
|
|
184
|
+
const deepest = new Map();
|
|
185
|
+
for (const sample of step.samples) {
|
|
186
|
+
for (const polygon of [sample.footprintIn, ...sample.mouthsIn]) {
|
|
187
|
+
const outside = polygonOutsideBox(polygon, bounds);
|
|
188
|
+
if (outside.worstIn > PERIMETER_TOLERANCE_IN && outside.worstIn > worstOutside.worstIn) {
|
|
189
|
+
worstOutside = {
|
|
190
|
+
worstIn: outside.worstIn,
|
|
191
|
+
t: sample.t,
|
|
192
|
+
pointIn: outside.worstPointIn ?? { xIn: 0, yIn: 0 },
|
|
193
|
+
};
|
|
194
|
+
}
|
|
195
|
+
for (const obstacle of obstacles) {
|
|
196
|
+
const overlap = polygonOverlapsBox(polygon, obstacleBox(obstacle));
|
|
197
|
+
if (!overlap.overlaps)
|
|
198
|
+
continue;
|
|
199
|
+
const seen = deepest.get(obstacle.id);
|
|
200
|
+
if (seen === undefined || overlap.penetrationIn > seen.penetrationIn) {
|
|
201
|
+
deepest.set(obstacle.id, { penetrationIn: overlap.penetrationIn, t: sample.t });
|
|
202
|
+
}
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
if (worstOutside.worstIn > 0) {
|
|
207
|
+
findings.push({
|
|
208
|
+
severity: "error",
|
|
209
|
+
stepId: step.id,
|
|
210
|
+
t: worstOutside.t,
|
|
211
|
+
code: "PERIMETER",
|
|
212
|
+
message: `The footprint leaves the field by ${worstOutside.worstIn.toFixed(2)} in.`,
|
|
213
|
+
geometry: { pointIn: worstOutside.pointIn },
|
|
214
|
+
});
|
|
215
|
+
}
|
|
216
|
+
for (const [obstacleId, hit] of deepest) {
|
|
217
|
+
findings.push({
|
|
218
|
+
severity: "error",
|
|
219
|
+
stepId: step.id,
|
|
220
|
+
t: hit.t,
|
|
221
|
+
code: "STRUCTURE",
|
|
222
|
+
message: `The footprint overlaps ${obstacleId} by ${hit.penetrationIn.toFixed(2)} in at its deepest.`,
|
|
223
|
+
geometry: { obstacleId, penetrationIn: hit.penetrationIn },
|
|
224
|
+
});
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
return findings;
|
|
228
|
+
}
|
|
229
|
+
/** True when any finding is an error, which is what `zenith validate` exits non-zero on. */
|
|
230
|
+
export const hasErrors = (findings) => findings.some((finding) => finding.severity === "error");
|
|
231
|
+
//# sourceMappingURL=check.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"check.js","sourceRoot":"","sources":["../src/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Finding, PlanStep } from "../types.js";
|
|
2
|
+
/**
|
|
3
|
+
* HEADING: where the file asks for a heading the robot will not hold.
|
|
4
|
+
*
|
|
5
|
+
* - warning: a `linear` heading that asks one segment for more than half a turn. The runtime hands
|
|
6
|
+
* Pedro that segment's two headings and Pedro turns the short way, so the robot goes round the
|
|
7
|
+
* other way from the one the file wrote. The preview already draws the short way; this says so.
|
|
8
|
+
* - info: a `facePoint` heading with a non-zero `offsetRad`, which the robot runtime does not pass
|
|
9
|
+
* to Pedro yet.
|
|
10
|
+
*
|
|
11
|
+
* HEADING_RANGES (error): a `piecewise` heading whose ranges do not run from 0 to 1 in order with no
|
|
12
|
+
* gap and no overlap. Pedro's `PiecewiseInterpolator` throws on the robot for exactly these, so the
|
|
13
|
+
* file cannot run. Inside ranges that are fine, a `linear` range over half a turn and a `facePoint`
|
|
14
|
+
* range with an offset raise the same HEADING findings as a whole-step heading.
|
|
15
|
+
*/
|
|
16
|
+
export declare function checkHeading(steps: readonly PlanStep[]): Finding[];
|
|
17
|
+
//# sourceMappingURL=heading.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"heading.d.ts","sourceRoot":"","sources":["../../src/checks/heading.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAErD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,YAAY,CAAC,KAAK,EAAE,SAAS,QAAQ,EAAE,GAAG,OAAO,EAAE,CA4DlE"}
|