no-please
v1.0.0
Published
Reasons to say no, in five escalating levels of politeness. No instance required.
Downloads
12
Maintainers
Readme
no-please
Reasons to say no, in five escalating levels of politeness.
This package returns a string. That's it. That's the package.
It has no dependencies, because it would be genuinely difficult to need any. It has 380 lines of build tooling and type definitions wrapped around what is, functionally, an array of excuses. I'm aware. We're all aware.
Install
npm install no-pleaseYes, you are adding a dependency for this. No, I won't stop you. Boundaries are the whole theme here and I'm not going to violate mine by lecturing you about yours.
Use it
import noPlease from 'no-please';
noPlease(); // 'Nah, I'm good.'
noPlease('polite'); // "I'd love to, but my calendar has other plans for me."
noPlease('extreme'); // 'That is a no so large it has its own weather system.'No new. No NoPleaseFactory. No .init() you'll forget to call and then spend forty minutes debugging. You call the function, it says no. This is the one design decision in the entire project I'm proud of.
Levels
| Level | For |
|---|---|
| polite | People whose opinion of you matters |
| casual | Default. How you actually talk |
| rude | People who booked the meeting at 4:45pm on a Friday |
| extreme | Recreational use only |
| poet | You own a fountain pen and we both know it |
Anything else throws a TypeError that tells you the valid levels, which is more helpful error handling than the problem strictly warrants.
API
The API section. For an API with one function in it.
noPlease(level?)
Returns one excuse. level defaults to 'casual'.
noPlease('rude'); // 'Absolutely not. Next question.'noPlease(options?)
For when a string is not enough ceremony.
noPlease({ level: 'poet' });
noPlease({ level: 'rude', random: () => 0 }); // deterministic, for testsrandom exists purely so your snapshot tests don't flake. You're welcome. It's the only feature in here that came from an actual engineering concern.
noPlease.all(level?)
Every excuse at that level, as a fresh array. Mutate it all you want, it's a copy.
noPlease.levels
['polite', 'casual', 'rude', 'extreme', 'poet']. Build a dropdown out of your refusals. Live your truth.
Works in your framework
It's a synchronous function that returns a string and touches nothing. It works everywhere. But the internet demands a compatibility section, so:
React
import noPlease from 'no-please';
function DeclineButton() {
const [excuse, setExcuse] = useState('');
return (
<>
<button onClick={() => setExcuse(noPlease('polite'))}>Decline</button>
<p>{excuse}</p>
</>
);
}There is no useNoPlease() hook. A hook would mean a React peer dependency, a rules-of-hooks footgun, and one more thing to version. It's a function. Call it.
Next.js
Works in server components, client components, route handlers, and middleware. Ships both ESM and CJS builds and imports nothing, so there is no 'use client' boundary to negotiate.
export async function GET() {
return Response.json({ reason: noPlease('rude') });
}NestJS
import { Injectable } from '@nestjs/common';
import noPlease from 'no-please';
@Injectable()
export class ExcuseService {
decline(): string {
return noPlease('polite');
}
}Do not put this in a provider and inject it. I know you want to. Resist.
Express
const express = require('express');
const noPlease = require('no-please');
app.get('/no', (req, res) => res.send(noPlease(req.query.level)));require() hands you the function directly, not { default: fn }. That took a build script to guarantee and I'd like exactly one person to notice.
TypeScript
Fully typed. The Level union is exported, so your editor will autocomplete five string literals at you.
import noPlease, { type Level } from 'no-please';FAQ
Is this a joke? It's a functioning, tested, typed, dual-format npm package. Those two things aren't mutually exclusive, which is arguably the problem with this whole ecosystem.
Can you add more excuses?
Sure. PRs welcome. Please put them in the right level; a polite excuse that lands in extreme will get someone fired and it won't be me.
Can you add i18n / an LLM / a plugin system?
noPlease('extreme');Contributing
Fork it, add strings to src/reasons.ts, run npm test, open a PR. The test suite is more rigorous than the subject matter deserves and I'd appreciate it if you kept it green.
License
MIT. Say no freely, commercially, and without attribution.
