spine-rigc 1.0.1 → 1.0.2

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spine-rigc",
3
- "version": "1.0.1",
3
+ "version": "1.0.2",
4
4
  "description": "Rig compiler for Spine — declarative rig specs in, Spine 4.3 skeleton data out, verified by a spine-core round-trip. Built so AI agents can author rigs and check their own work; the output imports into the Spine editor.",
5
5
  "type": "module",
6
6
  "bin": {
package/src/atlas.ts CHANGED
@@ -431,11 +431,12 @@ export function rewritePageNames(parsed: ParsedAtlas, rename: (name: string, ind
431
431
  *
432
432
  * This is what `--atlas-in` re-emits (issue #803). A pack's blank lines are its
433
433
  * packer's, not its content: a 3.8-era packer begins every file with one, and
434
- * `A07_ATLAS_TEXT_SHAPE` — which checks the text rigc writes — refused the
435
- * re-emission at `line 1`. What makes dropping them safe is what they mean to
436
- * the reader that owns the format: in `TextureAtlas` a run of blank lines ends a
437
- * page block exactly as one blank line does, and a run before the first page is
438
- * read as nothing. Measured through the runtime, `"\n" + text`, `"\n\n" + text`
434
+ * `A07_ATLAS_TEXT_SHAPE` — which checks the text rigc writes — refuses a blank
435
+ * line before the first page block, two side by side, and one after the last
436
+ * page block, each by its own sentence. What makes dropping them safe is what
437
+ * they mean to the reader that owns the format: in `TextureAtlas` a run of
438
+ * blank lines ends a page block exactly as one blank line does, and a run before
439
+ * the first page is read as nothing. Measured through the runtime, `"\n" + text`, `"\n\n" + text`
439
440
  * and `text` load to the same pages and regions (`PKR63`, `PKR64`).
440
441
  *
441
442
  * ⚠️ One reading is NOT the same, and it moves toward rigc's: the runtime's
@@ -523,9 +524,9 @@ export const PACK_NO_ROTATE = 0;
523
524
  * the trailing newline was appended unconditionally. That one byte contradicts
524
525
  * the paragraph above it: a blank line is the separator that sits BETWEEN page
525
526
  * blocks, so a file consisting of one is a separator with nothing on either side.
526
- * `A07_ATLAS_TEXT_SHAPE` then read it as a malformed page block and refused the
527
- * compiler's own output, which is how a rig with nothing to draw became a red
528
- * gate on a file nobody had written wrong.
527
+ * `A07_ATLAS_TEXT_SHAPE` reads a file with no non-blank line as having no page
528
+ * block and reports SKIP, and refuses a blank line that trails a page block as
529
+ * `the file ends with a blank line`.
529
530
  *
530
531
  * The runtime cannot tell the two apart — `new TextureAtlas('')`,
531
532
  * `new TextureAtlas('\n')` and `new TextureAtlas('\n\n')` all come back with
package/src/compile.ts CHANGED
@@ -3869,7 +3869,7 @@ function deferredAttachmentRefusal(type: string, where: string, how: string): st
3869
3869
  return (
3870
3870
  `${where}: this attachment is a "${type}"${how} — ${DEFERRED_ATTACHMENTS[type]}. ` +
3871
3871
  `rigc does not emit it yet, deliberately: it emits ${EMITTED_ATTACHMENT_TYPES.join(', ')}, and a point ` +
3872
- 'appears nowhere in the benchmark corpus (docs/SPEC_COVERAGE.md parts 3-1 and 4-2), so it is not on the ' +
3872
+ 'appears nowhere in the benchmark corpus, so it is not on the ' +
3873
3873
  "ladder's critical path. docs/SPEC_COVERAGE.md part 1-6 is the row this sentence reads " +
3874
3874
  'from, and it is what an implementation would have to carry.'
3875
3875
  );
package/src/generation.ts CHANGED
@@ -115,7 +115,8 @@ export function spineGeneration(version: string): SpineGeneration | null {
115
115
  export const TOPLEVEL_CONSTRAINT_ARRAYS: readonly string[] = ['ik', 'transform', 'path', 'physics', 'slider'];
116
116
 
117
117
  /**
118
- * The bone key 4.2 spelled `transform` and 4.3 spells `inherit`.
118
+ * The bone key 4.0 and 4.1 spelled `transform`, renamed `inherit` in 4.2 and
119
+ * spelled that way by 4.3.
119
120
  *
120
121
  * The old key does not throw and does not warn — it is an unknown field, so the
121
122
  * bone falls back to Normal inheritance (#706 row 6, and
package/src/ladder.ts CHANGED
@@ -34,7 +34,7 @@ export interface Rung {
34
34
  id: string;
35
35
  /** Directory under `examples/`. */
36
36
  example: string;
37
- /** One line on what this rung is testing, from SPEC_COVERAGE part 4-1. */
37
+ /** One line on what this rung is testing, from docs/SURVEY_2026-08-22.md part 4-1. */
38
38
  gates: string;
39
39
  skeletons: RungSkeleton[];
40
40
  }
package/src/rig.ts CHANGED
@@ -989,10 +989,10 @@ export interface RigPathAttachment extends RigVertexGeometry {
989
989
  * an unknown `type` and drop the attachment without a word
990
990
  * (`SkeletonJson.ts:653`).
991
991
  *
992
- * 🚧 It appears nowhere in the benchmark corpus (SPEC_COVERAGE parts 3-1 and
993
- * 4-2), so it is not on the ladder's critical path — which is the reason it is
994
- * deferred rather than an oversight. `linkedmesh` stood here beside it until
995
- * issue #691; `RigLinkedMeshAttachment` is the shape that replaced it.
992
+ * 🚧 It appears nowhere in the benchmark corpus, so it is not on the ladder's
993
+ * critical path — which is the reason it is deferred rather than an oversight.
994
+ * `linkedmesh` stood here beside it until issue #691; `RigLinkedMeshAttachment`
995
+ * is the shape that replaced it.
996
996
  */
997
997
  export interface RigUnimplementedAttachment {
998
998
  type: 'point';
package/src/validate.ts CHANGED
@@ -1205,22 +1205,27 @@ export function validate(input: ValidateInput): ValidateReport {
1205
1205
  // for want of a SUBJECT only when its reason is one of those constants.
1206
1206
  return skip('A07_ATLAS_TEXT_SHAPE', SKIP_NO_ATLAS_PAGE);
1207
1207
  }
1208
- // A blank line before the first page name is named as that (issue #803). It
1209
- // used to reach the loop below with `expectPage` already true and be read as
1210
- // a SECOND blank line — `line 1: consecutive blank lines`, where there is no
1211
- // line 0 to be consecutive with — and a run of k of them printed k findings.
1212
- // The verdict is unchanged: rigc writes no leading blank line
1213
- // (`writeAtlasText`, and `--atlas-in` through `canonicalAtlasShape`), so a file
1214
- // that has one was written by something else and is still refused. What
1215
- // changed is that the run is one finding, stating what it is and how long.
1208
+ // A blank line at either END of the file is named as that end (issues #803,
1209
+ // #810), and a run of them is one finding stating its length. They are taken
1210
+ // off both ends before the walk below, so the walk sees the page blocks and
1211
+ // the blank lines between them and nothing else: a blank line after the last
1212
+ // region is not a page block, and "consecutive blank lines" and "the last
1213
+ // page block declares no region" are about blocks. `TextureAtlas` reads a
1214
+ // blank at either end as nothing (`TextureAtlas.js:98-100` skips the leading
1215
+ // run, `:116-118` ends a page block on each blank line), and rigc writes
1216
+ // neither (`writeAtlasText`, and `--atlas-in` through `canonicalAtlasShape`),
1217
+ // so a file that has one was written by something else and is refused.
1216
1218
  let leading = 0;
1217
1219
  while (leading < atlasLines.length && atlasLines[leading].trim().length === 0) leading++;
1218
1220
  if (leading > 0) {
1219
1221
  fail('A07_ATLAS_TEXT_SHAPE', `line 1: the file begins with ${leading === 1 ? 'a blank line' : `${leading} blank lines`}`);
1220
1222
  }
1223
+ let trailing = 0;
1224
+ while (trailing < atlasLines.length - leading && atlasLines[atlasLines.length - 1 - trailing].trim().length === 0) trailing++;
1225
+ const blockEnd = atlasLines.length - trailing;
1221
1226
  let expectPage = true;
1222
1227
  let sawRegionForPage = false;
1223
- for (let i = leading; i < atlasLines.length; i++) {
1228
+ for (let i = leading; i < blockEnd; i++) {
1224
1229
  const line = atlasLines[i];
1225
1230
  if (line.trim().length === 0) {
1226
1231
  if (expectPage) fail('A07_ATLAS_TEXT_SHAPE', `line ${i + 1}: consecutive blank lines`);
@@ -1242,8 +1247,9 @@ export function validate(input: ValidateInput): ValidateReport {
1242
1247
  }
1243
1248
  sawRegionForPage = true;
1244
1249
  }
1245
- if (!sawRegionForPage && atlasLines.length) {
1246
- fail('A07_ATLAS_TEXT_SHAPE', 'the last page block declares no region');
1250
+ if (!sawRegionForPage) fail('A07_ATLAS_TEXT_SHAPE', 'the last page block declares no region');
1251
+ if (trailing > 0) {
1252
+ fail('A07_ATLAS_TEXT_SHAPE', `line ${blockEnd + 1}: the file ends with ${trailing === 1 ? 'a blank line' : `${trailing} blank lines`}`);
1247
1253
  }
1248
1254
  });
1249
1255
 
@@ -1904,14 +1910,14 @@ export function validate(input: ValidateInput): ValidateReport {
1904
1910
  });
1905
1911
 
1906
1912
  // --- A02: no bone.transform key ------------------------------------------
1907
- // 4.3 renamed it to `inherit`; the old key loads and silently falls back to
1908
- // Normal inheritance (case 6b). The key itself is `generation.ts`'s, for
1913
+ // 4.2 renamed it to `inherit`, and 4.3 kept that spelling; the old key loads
1914
+ // and silently falls back to Normal inheritance (case 6b). The key itself is `generation.ts`'s, for
1909
1915
  // A01's reason.
1910
1916
  check('A02_NO_BONE_TRANSFORM_KEY', () => {
1911
1917
  const bones = Array.isArray(raw?.bones) ? (raw.bones as unknown[]) : [];
1912
1918
  for (const bone of bones) {
1913
1919
  if (isObj(bone) && LEGACY_BONE_INHERIT_KEY in bone) {
1914
- fail('A02_NO_BONE_TRANSFORM_KEY', `bone "${String(bone.name)}" uses 4.2's "transform"; 4.3 wants "inherit"`);
1920
+ fail('A02_NO_BONE_TRANSFORM_KEY', `bone "${String(bone.name)}" uses "transform", the key 4.0 and 4.1 spelled; 4.2 and 4.3 spell it "inherit"`);
1915
1921
  }
1916
1922
  }
1917
1923
  });