Skip to content

Scale-reference 1.0: TypeScript, built package, named functions - #3

Merged
YauhenBichel merged 2 commits into
mainfrom
feat/v1-typescript
Sep 13, 2026
Merged

YauhenBichel merged 2 commits into
mainfrom
feat/v1-typescript

Conversation

@YauhenBichel

@YauhenBichel YauhenBichel commented Sep 13, 2026 •

Copy link
Copy Markdown
Member

This is the pilot for the 1.0 redesign that followed the critical review. scale-reference goes first because it is pure logic with no native code. Once this is merged, health-data and photo-quality follow the same pattern.

Why

The review tested the 0.2.0 package from the outside:

Consumer 0.2.0
Node require / import ERR_MODULE_NOT_FOUND (extensionless ESM source shipped as-is)
Jest with default settings SyntaxError: Unexpected token 'export'
TypeScript, strict TS7016, no types
publint "ESM interpreted as CJS" on every file
arethetypeswrong "does not contain types"

What changes

Packaging:

  • Written in TypeScript, strict with noUncheckedIndexedAccess.
  • Built with react-native-builder-bob into lib/commonjs and lib/module, each with its own type declarations.
  • Exposed through an exports map with import and require conditions, plus sideEffects: false, engines and "type": "commonjs".
  • prepack builds the package, so npm pack and npm publish always contain fresh lib/.

API (1.0, breaking; nothing was published):

  • Named functions replace the static class: scaleFromEllipse, toMillimetres, toSquareMillimetres, scalesAreComparable, explainRefusal. Constants are DEFAULT_OPTIONS and REFERENCE_OBJECTS. These can be tree-shaken and mocked, and can't be reassigned.
  • scaleFromEllipse always returns a frozen Scale, which is a discriminated union. mmPerPixel is a number only after checking usable.
  • Unreadable input, including no ellipse at all, is reason: 'invalid_input' instead of null. Numeric strings are no longer silently accepted.
  • Only programming errors throw (TypeError for an unknown or invalid option). A photo that can't be measured is a result.
  • scalesAreComparable takes {tolerance} and validates it.

Quality gates (CI):

  • check: ESLint (typescript-eslint strict type-checked) + Prettier, tsc, Jest with a 100% coverage threshold, and the build.
  • package: publint --strict, arethetypeswrong --pack, and the tarball allowlist, updated for lib/.
  • consumer (new): packs the package, installs it in a fresh project and loads it with require and import, once each with npm, Yarn 1, Yarn 4 Plug'n'Play, Yarn 4 node-modules, pnpm and Bun. The npm run also checks Jest with default settings, and strict TypeScript in node16 (CommonJS and ESM files) and bundler resolution, including that mmPerPixel can't be used before checking usable.
  • Dependabot for npm and GitHub Actions.

Release: the version must have a CHANGELOG section. The workflow runs lint, types, tests and package checks, builds once, then publishes with --ignore-scripts through trusted publishing. Publishing to npm covers every package manager and Expo, and the README now shows the install command for each.

Docs: README (install for all managers, a compatibility table, API table, upgrading from 0.x), CONTRIBUTING (design rules, commands), and a new CHANGELOG.

How it was checked (locally)

  • Lint, Prettier and tsc are clean. 28 tests pass at 100% statements, branches, functions and lines.
  • publint --strict: no errors. attw --pack: "No problems found", with node10, node16 from CommonJS, node16 from ESM and bundler all green.
  • The consumer check passes for all six package managers. npm, Yarn 1, Yarn 4 PnP, Yarn 4 node-modules, pnpm and Bun each install the packed tarball and load it with require and import. The npm run also passes the default-settings Jest project and strict TypeScript in node16 and bundler resolution.
  • The root package.json is "type": "module", and bob gives lib/commonjs its own commonjs marker. Without the root marker, Yarn 4 Plug'n'Play generates no ESM loader, and a plain import failed with ERR_MODULE_NOT_FOUND. I reproduced that, confirmed pnpEnableEsmLoader: true fixes it, and chose the root marker so consumers need no Yarn setting. The Jest-only Babel config is babel.config.cjs as a result.
  • The tarball allowlist was checked against the real 36-file tarball.
  • On CI, all 8 jobs pass on 5496930, including every package manager on Linux. The first run failed the package job: publint packs without running prepack, so a fresh checkout had no lib/, which a leftover local build had hidden. check:package now builds first, and I re-checked it from a clean copy.

For the app

The MoleCare app only uses this package in its own ScaleReference test. After merge, a small app PR updates that test and the adapter to the new names and bumps the pin.

🤖 Generated with Claude Code

YauhenBichel and others added 2 commits September 13, 2026 12:52
- Write the package in TypeScript and publish built code: CommonJS and ES
  modules with their own type declarations behind an exports map
  (react-native-builder-bob). It now loads from Node require/import, Jest
  with default settings and strict TypeScript (node16 and bundler).
- Replace the static ScaleReference class with named functions and frozen
  constants; scaleFromEllipse always returns a frozen Scale union, with
  'invalid_input' instead of null.
- CI: ESLint (typescript-eslint strict), Prettier, tsc, Jest with 100%
  coverage, publint, arethetypeswrong, and a consumer check that installs
  the packed tarball with npm, Yarn 1, Yarn 4 PnP and node-modules, pnpm
  and Bun.
- Release requires a CHANGELOG section and builds once before publishing.
- Dependabot, CHANGELOG, README and CONTRIBUTING for 1.0.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
publint packs without running prepack, so on a fresh checkout it found no
lib/. Locally an earlier build hid this.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@YauhenBichel
YauhenBichel merged commit 7c60287 into main Sep 13, 2026
8 checks passed
@YauhenBichel
YauhenBichel deleted the feat/v1-typescript branch September 13, 2026 11:59
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant