1#!/usr/bin/env node
2
3const invariant = require('invariant');
4const path = require('path');
5const fs = require('fs');
6
7const cwd = process.cwd();
8const workspaceRoot = path.resolve(__dirname, '../../');
9const pkg = require(path.resolve(cwd, 'package.json'));
10
11const hasReact = [
12 'dependencies',
13 'optionalDependencies',
14 'peerDependencies',
15].some(dep => pkg[dep] && pkg[dep].react);
16
17const hasNext = [
18 'dependencies',
19 'optionalDependencies',
20 'peerDependencies',
21].some(dep => pkg[dep] && pkg[dep].next);
22
23const normalize = name =>
24 name
25 .replace(/[@\s/.]+/g, ' ')
26 .trim()
27 .replace(/\s+/, '-')
28 .toLowerCase();
29
30const name = normalize(pkg.name);
31
32const posixPath = x => path.normalize(x).split(path.sep).join('/');
33
34const is = (a, b) => posixPath(a) === posixPath(b);
35
36invariant(
37 pkg.publishConfig.provenance === true,
38 'package.json:publishConfig.provenance must be set to true'
39);
40
41if (pkg.name.startsWith('@urql/')) {
42 invariant(
43 pkg.publishConfig.access === 'public',
44 'package.json:publishConfig.access must be set to public for @urql/* packages'
45 );
46}
47
48invariant(!is(cwd, workspaceRoot), 'prepare-pkg must be run in a package.');
49
50invariant(
51 fs.existsSync(pkg.source || 'src/index.ts'),
52 'package.json:source must exist'
53);
54
55if (hasReact && !hasNext) {
56 invariant(
57 is(pkg.main, path.join('dist', `${name}.js`)),
58 'package.json:main path must end in `.js` for packages depending on React.'
59 );
60
61 invariant(
62 is(pkg.module, path.join('dist', `${name}.es.js`)),
63 'package.json:module path must end in `.es.js` for packages depending on React.'
64 );
65} else {
66 invariant(
67 is(pkg.main, path.join('dist', `${name}`)),
68 'package.json:main path must be valid and have no extension'
69 );
70
71 invariant(
72 is(pkg.module, path.join('dist', `${name}.mjs`)),
73 'package.json:module path must be valid and ending in .mjs'
74 );
75}
76
77invariant(
78 is(pkg.types, path.join('dist', `${name}.d.ts`)),
79 'package.json:types path must be valid'
80);
81
82invariant(
83 is(pkg.repository.directory, path.relative(workspaceRoot, cwd)),
84 'package.json:repository.directory path is invalid'
85);
86
87invariant(pkg.sideEffects === false, 'package.json:sideEffects must be false');
88
89invariant(!!pkg.author, 'package.json:author must be defined');
90
91invariant(pkg.license === 'MIT', 'package.json:license must be "MIT"');
92
93invariant(
94 Array.isArray(pkg.files) &&
95 pkg.files.some(x => path.normalize(x).startsWith('dist')) &&
96 pkg.files.some(x => path.normalize(x) === 'LICENSE'),
97 'package.json:files must include "dist" and "LICENSE"'
98);
99
100if (pkg.dependencies && pkg.dependencies['@urql/core']) {
101 invariant(
102 !!pkg.peerDependencies && !!pkg.peerDependencies['@urql/core'],
103 'package.json:peerDependencies must contain @urql/core.'
104 );
105}
106
107if (pkg.peerDependencies && pkg.peerDependencies['@urql/core']) {
108 invariant(
109 !!pkg.dependencies && !!pkg.dependencies['@urql/core'],
110 'package.json:dependencies must contain @urql/core.'
111 );
112}
113
114for (const key in pkg.peerDependencies || {}) {
115 const dependency = pkg.peerDependencies[key];
116 invariant(
117 key !== 'react' || key !== 'preact' || !dependency.includes('>='),
118 `Peer Dependency "${key}" must not contain ">=" (greater than) range`
119 );
120}
121
122if (hasReact && !hasNext) {
123 invariant(
124 !pkg.exports,
125 'package.json:exports must not be added for packages depending on React.'
126 );
127} else {
128 invariant(
129 !!pkg.exports,
130 'package.json:exports must be added and have a "." entry'
131 );
132 invariant(!!pkg.exports['.'], 'package.json:exports must have a "." entry');
133 invariant(
134 !!pkg.exports['./package.json'],
135 'package.json:exports must have a "./package.json" entry'
136 );
137
138 for (const key in pkg.exports) {
139 const entry = pkg.exports[key];
140 if (entry === './package.json') continue;
141
142 const entryName = normalize(key);
143 const bundleName = entryName ? `${name}-${entryName}` : name;
144 invariant(
145 fs.existsSync(entry.source),
146 `package.json:exports["${key}"].source must exist`
147 );
148
149 invariant(
150 is(entry.require, `./dist/${bundleName}.js`),
151 `package.json:exports["${key}"].require must be valid`
152 );
153
154 invariant(
155 is(entry.import, `./dist/${bundleName}.mjs`),
156 `package.json:exports["${key}"].import must be valid`
157 );
158
159 invariant(
160 is(entry.types, `./dist/${bundleName}.d.ts`),
161 'package.json:types path must be valid'
162 );
163
164 invariant(
165 Object.keys(entry)[0] === 'types',
166 'package.json:types must come first'
167 );
168 }
169}
170
171fs.copyFileSync(
172 path.resolve(workspaceRoot, 'LICENSE'),
173 path.resolve(cwd, 'LICENSE'),
174 0
175);