npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@jpcw/configs

v2.8.1

Published

Shared TypeScript / ESLint / Prettier configs and CLI helpers for JPCW projects (SuiteScript, React, and React Native presets).

Readme

@jpcw/configs

Opinionated TypeScript / ESLint / Prettier presets and a small CLI: scaffold a fully configured project in one command, keep every repo on the same toolchain, and run a quieter tsc --watch.

In honor and memory of Forrest Jones. C# > TS.

Every TypeScript repo carries the same half-dozen config files, and they drift the moment they're copy-pasted. Here, your repo takes one dev dependency plus a handful of one-line files that extend a preset. Update the package, run fleet --fix, and every repo follows.

Contents: Quick start · Presets · Scaffolded files · CLI: init / doctor / fleet / upgrade / format / watch / setup-watch / NetSuite commands · Migrating an existing repo · Versioning

Quick start

mkdir my-project && cd my-project
git init
npx -p @jpcw/configs jpcw-configs init suitescript --pm yarn   # or react | react-native
yarn install                                                   # match your --pm

That's a complete setup: configs, VS Code workspace, CI, pre-commit hook, Claude Code notes, watch task. init is idempotent — re-running only adds what's missing.

After scaffolding:

  • suitescript — replace PROJECT_NAME and REPLACE_WITH_SDF_AUTH_ID_* in package.json. For full strict mode, point tsconfig extends at @jpcw/configs/suitescript/tsconfig.strict.json.
  • react-native — assumes Expo + Expo Router; on bare RN, drop expo-router and adjust main.
  • VS Code asks once to allow automatic tasks (the watch task) — accept it.

Presets

| Preset | Target | Notes | |---|---|---| | suitescript | NetSuite SuiteScript 2.x | AMD/ES2021 emit, CRLF, NetSuite-specific lints (below) | | react | React web | Vite, ES2022, JSX, LF, jsx-a11y | | react-native | React Native / Expo | no DOM lib, __DEV__ global, jsx: react-native |

The suitescript preset lints for the actual NetSuite runtime, catching deploy-time failures at lint time:

  • Node.js built-in imports are errors — they don't exist in the NetSuite runtime.
  • Files under SuiteScripts/ require the @NApiVersion / @NScriptType JSDoc tags; miscased tags (@NAPIVersion) break NetSuite's loader and are auto-corrected by eslint --fix.
  • Entry-point files (.ue.ts, .mr.ts, .sch.ts, …) must declare the @NScriptType matching their suffix and export that type's entry-point function(s).
  • A separate tsconfig.spa.json covers React SPAs bundled into a Suitelet (src/spa/).

Scaffolded files

| File | Purpose | |---|---| | tsconfig.json | Extends the preset; project paths/include filled in | | eslint.config.mjs, prettier.config.mjs | One-line re-exports of the preset | | package.json | Pinned deps; lint, format (compiled output excluded), typecheck, watch, knip scripts (+ sb/prod/ns:* for suitescript); lint-staged + hook-wiring postinstall | | .editorconfig, .gitattributes | Tabs + line endings pinned (CRLF for suitescript, LF otherwise), independent of each machine's autocrlf | | .gitignore, .prettierignore | Per-preset ignores | | .vscode/settings.json | Format-on-save, ESLint flat-config mode, search/watcher excludes for build output (editor-only — no effect on git or uploads) | | .vscode/extensions.json | Recommended extensions: ESLint, Prettier, EditorConfig, Claude Code, per-preset extras | | .vscode/tasks.json | The watch task, auto-started on folder open | | knip.json | Dead-code audit (yarn knip) with per-preset entry points — for suitescript the report reads as "code nothing deployed can reach" | | .githooks/pre-commit | lint-staged on staged files only | | .github/workflows/ci.yml | Thin caller of this repo's central reusable-ci.yml (lint + typecheck + format on push/PR) | | CLAUDE.md, .claude/settings.json | Per-preset Claude Code notes + permission allowlist | | tsconfig.spa.json | suitescript only — Suitelet-served React SPA build | | .yarnrc.yml | Yarn only — nodeLinker: node-modules (SDF tooling needs it) + npmPreapprovedPackages for @jpcw/* |

CLI

| Command | What it does | |---|---| | init <preset> | Scaffold a project (idempotent) | | doctor [preset] | Audit one repo for drift; --fix repairs additively | | fleet | doctor across every repo under a directory | | upgrade <preset> | Bump the managed toolchain to current versions | | format | Prettier, minus compiled output | | watch | Incremental tsc --watch with delta-only output | | setup-watch | Add the watch script + VS Code task to a repo | | write-project-json | Switch the target NetSuite account | | ns-whereami | Print which NetSuite account is active | | ns-upload | Upload File Cabinet files (multi-select capable) |

jpcw-configs init <preset>

Scaffolds a project with the preset's config files (full list). Idempotent — re-running only adds what's missing.

jpcw-configs init suitescript --pm yarn

| Flag | Default | Behavior | |---|---|---| | --pm <yarn\|npm\|bun> | yarn | Pins packageManager and drops in PM-specific files (e.g. .yarnrc.yml) | | --force | off | Overwrite an existing .gitignore (other existing files are always skipped) | | --latest | off | Follow up with upgrade <preset> so deps install at current versions, not the template pins |

jpcw-configs doctor [preset]

Audits an existing repo against its preset: missing scaffold files, package.json gaps, legacy .eslintrc*/.prettierrc* shadowing the flat config, a TS 7 install that breaks the toolchain, an @jpcw/configs pin a major behind. Preset is auto-detected; pass it only if detection fails.

jpcw-configs doctor            # report
jpcw-configs doctor --fix      # apply the additive fixes

--fix is additive only — copies missing files, fills package.json gaps, never overwrites or deletes (legacy configs are reported for manual cleanup). Exits non-zero while warnings/errors remain, so it works as a CI gate.

| Flag | Default | Behavior | |---|---|---| | --fix | off | Apply fixable findings | | --json | off | JSON findings instead of human output | | --pm <yarn\|npm\|bun> | auto | Package manager used when filling packageManager |

jpcw-configs fleet

doctor, across every repo at once: scans below cwd (or --root) for directories whose package.json declares @jpcw/configs, audits each, and prints one status line per repo with findings indented. Discovery recurses a few levels (grouping folders like ~/projects/<client>/<repo> work) but never descends into a matched repo, node_modules, or hidden directories. A preset improvement lands in all client repos with one command.

cd ~/projects && jpcw-configs fleet        # who's drifted?
cd ~/projects && jpcw-configs fleet --fix  # repair everywhere (doctor's additive-only guarantee)

| Flag | Default | Behavior | |---|---|---| | --fix | off | Apply doctor's fixable findings in each repo | | --root <dir> | cwd | Directory whose children are scanned |

jpcw-configs upgrade <preset>

The template pins are reproducible but go stale. upgrade resolves the managed dep set (read from the preset template, so it tracks automatically) to whatever is current the moment you run it, via your package manager.

jpcw-configs upgrade suitescript
jpcw-configs upgrade react-native --include-frameworks --dry-run
  • Toolchain (eslint, prettier, typescript, @types/*, vite, …) — always taken at @latest. Exception: typescript is capped at 6.x — TS 7's native compiler drops the JS compiler API (watch, type-aware linting) and AMD emit, so that move is a deliberate migration.
  • Framework / native (react, expo, react-native, …) — skipped unless --include-frameworks. Expo deps go through expo install so they stay SDK-correct, never npm-latest.

| Flag | Default | Behavior | |---|---|---| | --pm <yarn\|npm\|bun> | auto | Detected from packageManager / lockfile | | --include-frameworks | off | Also upgrade framework/native deps | | --dry-run | off | Print the commands without running them |

jpcw-configs format

Prettier over the project, skipping compiled output. Backs the format / format:write scripts and the lint-staged entry in the suitescript preset.

The suitescript tsconfig has no outDir — tsc emits foo.js next to foo.ts under src/FileCabinet, and both halves are committed because SDF deploys the .js. Letting Prettier reformat that output means every build rewrites it back in tsc's style, so a plain tsc dirties the whole File Cabinet with diffs that change nothing. Branches look like they have work in them when all that happened was a rebuild.

A blanket **/*.js exclusion would be wrong: SuiteScript 1.0 is JS-only, and plenty of early 2.x scripts predate the TypeScript move. Those are real sources and must keep getting formatted. What separates them is a sibling .ts — the same rule ns-upload uses to upload both halves of a pair — so the exclusion is computed per file, not globbed.

jpcw-configs format              # check (CI does this)
jpcw-configs format --write      # rewrite
jpcw-configs format --list       # which files get skipped, without running prettier

The suitescript ESLint preset applies the same rule to its ignores, so compiled output isn't linted or --fix'd either. The editor is the one place this rule can't reach — the Prettier extension reads only .prettierignore — so the scaffolded .vscode/settings.json turns format-on-save off for .js and leaves it to the commit hook. doctor flags repos that haven't done that.

Adopting this on an existing repo produces one settling commit: the files that were being reformatted revert to tsc's output the next time you build. After that the File Cabinet only shows up in git status when a script genuinely changed.

Across a fleet, doctor finds the repos still on whole-tree Prettier and fleet --fix migrates them all at once:

cd ~/projects && jpcw-configs fleet          # who's still churning?
cd ~/projects && jpcw-configs fleet --fix    # migrate every repo

Then, per repo: rebuild (yarn watch once, or tsc) and commit the revert.

jpcw-configs watch

Incremental TypeScript watch (type-check + emit, same compiler as tsc --watch) that reports the diff instead of re-printing every error each pass:

── 9:02:16 AM ── recompiling… ──────────────────────────

a.ts — fixed (was 1) ✔
b.ts — 1 error
  src/b.ts:3:7 TS2322: Type 'number' is not assignable to type 'string'.

Watching… ✖ 1 error in 1 file  (▼1)
  • Last line always carries the current state: ✖ 13 errors in 5 files (▼1) (▲ in red when the count rose).
  • Full diagnostics only for files whose error set changed — including ripple effects, tagged [affected by your change]. Errors print as path:line:col for IDE hyperlinking.
  • Uses the repo's own typescript install, so it always agrees with yarn typecheck.

| Flag | Default | Behavior | |---|---|---| | -p, --project <path> | nearest tsconfig.json | tsconfig to use | | --no-color | off | Disable ANSI colors (also honors NO_COLOR) |

jpcw-configs setup-watch

Adds the watch setup to an existing repo (new repos get it from init): the "watch": "jpcw-configs watch" script and the .vscode/tasks.json task that auto-starts on folder open. Idempotent; an existing tasks.json is left alone with instructions printed.

One manual step per repo/machine: allow automatic tasks when VS Code prompts (or Tasks: Manage Automatic Tasks → Allow).

NetSuite commands

jpcw-configs write-project-json --auth <id>

Writes a SuiteCloud project.json, making the account switch a one-line package.json script (the scaffolded sb / prod). Prints the account banner after writing, so a switch to PRODUCTION is never silent.

| Flag | Default | Meaning | |---|---|---| | --auth | required | SDF auth ID for the target account | | --asv | ERROR | accountSpecificValues (ERROR or WARNING) | | --out | project.json | Output path |

jpcw-configs ns-whereami

Prints the NetSuite account the nearest project.json targets, with PRODUCTION flagged loudly (an auth ID counts as non-prod when it contains sb / sand / tstdrv / dev). Run it before a batch of IDE uploads; scaffolded as yarn ns:whereami.

jpcw-configs ns-upload [files...]

Uploads File Cabinet files to the active account via suitecloud file:upload — a multi-file selection in one keystroke, where the IDE plugins handle one file at a time. Selecting either half of a .ts/.js pair uploads both. Files must live under src/FileCabinet. The banner (and --notify toast) names the target account, PRODUCTION flagged.

jpcw-configs ns-upload src/FileCabinet/SuiteScripts/jpcw/lib/a.lib.ts
jpcw-configs ns-upload --from-clipboard    # VS Code multi-select hook

| Flag | Default | Behavior | |---|---|---| | --from-clipboard | off | Read newline-separated paths from the clipboard (WSL, relative, or \\wsl.localhost\... UNC paths) | | --dry-run | off | Print the suitecloud command without running it | | --notify | off | Desktop notification (Windows toast from WSL, else notify-send) on finish/fail |

VS Code multi-select in one keystroke — a user-level task (Tasks: Open User Tasks) plus keybinding works in every SDF repo with no per-repo files:

// User Tasks — reveal: silent keeps focus in the editor; --notify toasts on finish
{ "label": "NS: Upload selected", "type": "shell",
  "command": "npx jpcw-configs ns-upload --from-clipboard --notify",
  "presentation": { "reveal": "silent", "focus": false, "panel": "shared", "clear": true } }
// keybindings.json — copies ALL selected explorer paths, then runs the task
{ "key": "shift+alt+y", "command": "runCommands",
  "args": { "commands": ["copyFilePath",
    { "command": "workbench.action.tasks.runTask", "args": "NS: Upload selected" }] },
  "when": "filesExplorerFocus" }

Migrating an existing repo

init is safe on a non-empty repo — it only adds what's missing.

  1. yarn add -D @jpcw/configs && npx jpcw-configs init suitescript (or react / react-native). Older repo? Follow with upgrade, or use init --latest.
  2. init skipped any tsconfig.json / eslint.config.mjs / prettier.config.mjs you already had. Delete yours and re-run, or point extends at the preset (e.g. "@jpcw/configs/suitescript/tsconfig.json").
  3. Delete legacy .eslintrc* / .prettierrc* files — ESLint and Prettier pick those up before the preset otherwise (doctor flags them).
  4. Verify: npx jpcw-configs doctor && yarn typecheck && yarn lint && yarn format.
  5. Suitescript repos: doctor --fix moves format off whole-tree Prettier (see format). Rebuild and commit the one-time revert of the compiled output.

Versioning

Semver. Breaking preset changes (rule removals, severity bumps) are major; new rules, lints, and CLI flags are minor. Per-version notes in CHANGELOG.md; maintainer notes in MAINTAINING.md.