Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

16: base optional package.json fields support #17

Merged
merged 1 commit into from
Aug 24, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 14 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,26 @@
"name": "smartbundle",
"private": true,
"version": "0.3.0-alpha.2",
"description": "",
"description": "zero-config bundler for npm packages",
"bin": "./src/bin.ts",
"type": "module",
"scripts": {
"test": "vitest",
"test:update-snapshots": "vitest -u"
},
"keywords": [],
"author": "",
"keywords": ["smartbundle", "bundler", "npm", "package", "typescript", "esm", "cjs"],
"author": {
"name": "Andrey Vassilyev",
"email": "[email protected]"
},
"repository": {
"type": "git",
"url": "https://github.com/xavescor/smartbundle"
},
"homepage": "https://github.com/xavescor/smartbundle",
"bugs": {
"url": "https://github.com/xavescor/smartbundle/issues"
},
"license": "MIT",
"devDependencies": {
"@types/node": "^20.14.11",
Expand Down
41 changes: 41 additions & 0 deletions src/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# SmartBundle - zero-config bundler for npm packages

## How to use
1) Create package.json like
```json
{
"name": "my-package",
"version": "1.0.0",
"private": true, // required for avoiding the accidental publishing
"type": "module",
"exports": {
".": "./src/index.ts" // entrypoint list for building the package
}
}
```
2) Run
```bash
npx smartbundle
```
3) Go to the `dist` folder and publish your package to the npm registry. The total package.json will be generated automatically.

## Features
- generate the most compatible package.json for any bundlers(webpack, rollup, esbuild, vite, etc) or runtimes(node, bun, deno, etc)
- validate package.json for common errors
- do not require any configuration files like tsconfig.json, eslintrc.json, etc
- but if you need to use them, you can use them by creating them manually like for the parcel bundler
- generate esm and cjs entrypoints for the package
- generate typescript typings for the package
- require only minimal package.json fields

## Known issues:
- does not generate fully compatible cjs typings for the entrypoints (#9)
- supports only `type: module` right now. It will be fixed before `v1.0.0` release.

## Motivation

Almost every npm package have the same build pipeline: build code, generate typescript typings, validate package.json, generate correct package.json for the bundlers and runtimes, blah-blah, etc.

I really like the [microbundle](https://github.com/developit/microbundle) project, but it requires a lot of extra configuration and is not zero-config. And more, the project is not maintained and does not support a lot of modern js features.

So I decided to create my own project to automate the build pipeline and save the developer's time for building packages.
24 changes: 24 additions & 0 deletions src/errors.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,4 +27,28 @@ export const errors = {
"The package.json contains typescript entrypoints, but the typescript package is not found. Please, install typescript@^5.0.0",
optionalDependenciesInvalid:
"The `optionalDependencies` field must be an Object<string, string>. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#optionaldependencies",
repositoryInvalid:
"The `repository` field must be an object with 'type' and 'url' properties or a string. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#repository",
keywordsInvalid:
"The `keywords` field must be an array of strings. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#keywords",
authorInvalid:
"The `author` field must be an object or a string. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#people-fields-author-contributors",
contributorsInvalid:
"The `contributors` field must be an array of objects or strings. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#people-fields-author-contributors",
licenseInvalid:
"The `license` field must be a string specifying the license. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#license",
devDependenciesInvalid:
"The `devDependencies` field must be an Object<string, string>. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#devdependencies",
peerDependenciesInvalid:
"The `peerDependencies` field must be an Object<string, string>. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#peerdependencies",
enginesInvalid:
"The `engines` field must be an object specifying version requirements. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#engines",
browserInvalid:
"The `browser` field must be a string or an object. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#browser",
fundingInvalid:
"The `funding` field must be an object or a string. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#funding",
osInvalid:
"The `os` field must be an array of strings. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#os",
cpuInvalid:
"The `cpu` field must be an array of strings. Please, verify the value. More info: https://docs.npmjs.com/cli/v10/configuring-npm/package-json#cpu",
};
108 changes: 108 additions & 0 deletions src/packageJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,58 @@ import z from "zod";
import { errors } from "./errors.js";
import { join } from "node:path";

// <region>
// For AI completion. Don't remove.
const allPackageJsonFields = [
"exports",
"name",
"version",
"private",
"description",
"dependencies",
"optionalDependencies",
"bin",
"repository",
"keywords",
"author",
"contributors",
"license",
"devDependencies",
"peerDependencies",
"engines",
"browser",
"funding",
"os",
"cpu"
];

const requiredFields = [
"exports",
"name",
"version",
"private"
];

const optionalFields = [
"description",
"dependencies",
"optionalDependencies",
"bin",
"repository",
"keywords",
"author",
"contributors",
"license",
"devDependencies",
"peerDependencies",
"engines",
"browser",
"funding",
"os",
"cpu"
]
// </region>

async function fileExists(filePath: string) {
try {
const stats = await fs.stat(filePath);
Expand Down Expand Up @@ -43,6 +95,62 @@ function createPackageJsonSchema(sourceDir: string) {
dependencies: dependencies(errors.dependenciesInvalid),
optionalDependencies: dependencies(errors.optionalDependenciesInvalid),
bin: z.string({ message: errors.binString }).optional(),
repository: z
.union([
z.string({ message: errors.repositoryInvalid }),
z.object({
type: z.string(),
url: z.string(),
}, { message: errors.repositoryInvalid }),
])
.optional(),
keywords: z
.array(z.string(), { message: errors.keywordsInvalid })
.optional(),
author: z
.union([
z.string({ message: errors.authorInvalid }),
z.object({
name: z.string({ message: errors.authorInvalid }).optional(),
email: z.string({ message: errors.authorInvalid }).optional(),
url: z.string({ message: errors.authorInvalid }).optional(),
}, { message: errors.authorInvalid })
])
.optional(),
contributors: z
.array(
z.union([
z.string({ message: errors.contributorsInvalid }),
z.object({}, { message: errors.contributorsInvalid })
])
)
.optional(),
license: z
.string({ message: errors.licenseInvalid })
.optional(),
devDependencies: dependencies(errors.devDependenciesInvalid),
peerDependencies: dependencies(errors.peerDependenciesInvalid),
engines: z
.record(z.string(), { message: errors.enginesInvalid })
.optional(),
browser: z
.union([
z.string({ message: errors.browserInvalid }),
z.record(z.string(), { message: errors.browserInvalid })
])
.optional(),
funding: z
.union([
z.string({ message: errors.fundingInvalid }),
z.object({}, { message: errors.fundingInvalid })
])
.optional(),
os: z
.array(z.string(), { message: errors.osInvalid })
.optional(),
cpu: z
.array(z.string(), { message: errors.cpuInvalid })
.optional(),
});
}
type PackageJsonSchema = ReturnType<typeof createPackageJsonSchema>;
Expand Down
12 changes: 12 additions & 0 deletions src/writePackageJson.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,18 @@ export async function writePackageJson(
exports: allExports,
dependencies: parsed.dependencies ?? undefined,
optionalDependencies: parsed.optionalDependencies ?? undefined,
repository: parsed.repository,
keywords: parsed.keywords,
author: parsed.author,
contributors: parsed.contributors,
license: parsed.license,
devDependencies: parsed.devDependencies,
peerDependencies: parsed.peerDependencies,
engines: parsed.engines,
browser: parsed.browser,
funding: parsed.funding,
os: parsed.os,
cpu: parsed.cpu,
};

await writeFile(`${outDir}/package.json`, JSON.stringify(res, null, 2));
Expand Down