next-imagetools 0.0.0-stage → 0.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +489 -2
- package/client.d.ts +138 -0
- package/dist/asset-loader.cjs +38 -0
- package/dist/config-MI8A5KvL.d.mts +27 -0
- package/dist/config-MI8A5KvL.d.mts.map +1 -0
- package/dist/config.cjs +7 -0
- package/dist/config.d.cts +26 -0
- package/dist/config.d.cts.map +1 -0
- package/dist/config.d.mts +2 -0
- package/dist/config.mjs +8 -0
- package/dist/config.mjs.map +1 -0
- package/dist/core.cjs +9 -0
- package/dist/core.d.cts +1 -0
- package/dist/core.d.mts +1 -0
- package/dist/core.mjs +2 -0
- package/dist/index.cjs +87 -0
- package/dist/index.d.cts +46 -0
- package/dist/index.d.cts.map +1 -0
- package/dist/index.d.mts +48 -0
- package/dist/index.d.mts.map +1 -0
- package/dist/index.mjs +88 -0
- package/dist/index.mjs.map +1 -0
- package/dist/loader.cjs +441 -0
- package/dist/shared-DNQObFGr.cjs +300 -0
- package/package.json +108 -3
|
@@ -0,0 +1,300 @@
|
|
|
1
|
+
// \0rolldown/runtime.js
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __copyProps = (to, from, except, desc) => {
|
|
9
|
+
if (from && typeof from === "object" || typeof from === "function") for (var keys = __getOwnPropNames(from), i = 0, n = keys.length, key; i < n; i++) {
|
|
10
|
+
key = keys[i];
|
|
11
|
+
if (!__hasOwnProp.call(to, key) && key !== except) __defProp(to, key, {
|
|
12
|
+
get: ((k) => from[k]).bind(null, key),
|
|
13
|
+
enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable
|
|
14
|
+
});
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(isNodeMode || !mod || !mod.__esModule || !__hasOwnProp.call(mod, "default") ? __defProp(target, "default", {
|
|
19
|
+
value: mod,
|
|
20
|
+
enumerable: true
|
|
21
|
+
}) : target, mod));
|
|
22
|
+
let node_fs_promises = require("node:fs/promises");
|
|
23
|
+
let node_path = require("node:path");
|
|
24
|
+
node_path = __toESM(node_path, 1);
|
|
25
|
+
let node_url = require("node:url");
|
|
26
|
+
let imagetools_core = require("imagetools-core");
|
|
27
|
+
let sharp = require("sharp");
|
|
28
|
+
sharp = __toESM(sharp, 1);
|
|
29
|
+
let node_crypto = require("node:crypto");
|
|
30
|
+
let node_fs = require("node:fs");
|
|
31
|
+
// package.json
|
|
32
|
+
var version = "0.0.0";
|
|
33
|
+
// src/shared.ts
|
|
34
|
+
const toParams = (directives) => directives === void 0 ? void 0 : new URLSearchParams(directives);
|
|
35
|
+
const DEFAULT_CACHE_DIR = "node_modules/.cache/next-imagetools";
|
|
36
|
+
function hash(parts) {
|
|
37
|
+
const h = (0, node_crypto.createHash)("sha1");
|
|
38
|
+
for (const p of parts) h.update(p);
|
|
39
|
+
return h.digest("hex");
|
|
40
|
+
}
|
|
41
|
+
const sweeps = /* @__PURE__ */ new Map();
|
|
42
|
+
/**
|
|
43
|
+
* The cache directory to use, or `undefined` when caching is disabled. With `retention` set, the
|
|
44
|
+
* first call in a process for a directory removes entries that haven't been used for that long;
|
|
45
|
+
* loaders have no end-of-build hook, so this is the one point every worker passes through.
|
|
46
|
+
*/
|
|
47
|
+
async function prepareCache(ctx, options) {
|
|
48
|
+
const { enabled = true, dir = DEFAULT_CACHE_DIR, retention } = options.cache ?? {};
|
|
49
|
+
if (!enabled) return void 0;
|
|
50
|
+
const resolved = node_path.default.resolve(ctx.rootContext ?? process.cwd(), dir);
|
|
51
|
+
(0, node_fs.mkdirSync)(resolved, { recursive: true });
|
|
52
|
+
if (retention !== void 0) {
|
|
53
|
+
let sweep = sweeps.get(resolved);
|
|
54
|
+
if (!sweep) sweeps.set(resolved, sweep = removeExpired(resolved, retention));
|
|
55
|
+
await sweep;
|
|
56
|
+
}
|
|
57
|
+
return resolved;
|
|
58
|
+
}
|
|
59
|
+
async function removeExpired(dir, retentionSeconds) {
|
|
60
|
+
const cutoff = Date.now() - retentionSeconds * 1e3;
|
|
61
|
+
const names = await (0, node_fs_promises.readdir)(dir);
|
|
62
|
+
await Promise.all(names.map(async (name) => {
|
|
63
|
+
const file = node_path.default.join(dir, name);
|
|
64
|
+
const info = await (0, node_fs_promises.stat)(file).catch(() => void 0);
|
|
65
|
+
if (info?.isFile() && info.mtimeMs < cutoff) await (0, node_fs_promises.rm)(file, { force: true });
|
|
66
|
+
}));
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* A cached encoding, or `undefined` to process the image again. Any read failure counts as a miss —
|
|
70
|
+
* including an entry another worker's retention sweep removed a moment ago.
|
|
71
|
+
*/
|
|
72
|
+
async function readCached(file) {
|
|
73
|
+
try {
|
|
74
|
+
const data = await (0, node_fs_promises.readFile)(file);
|
|
75
|
+
if (data.length === 0) return void 0;
|
|
76
|
+
const now = /* @__PURE__ */ new Date();
|
|
77
|
+
await (0, node_fs_promises.utimes)(file, now, now).catch(() => {});
|
|
78
|
+
return data;
|
|
79
|
+
} catch {
|
|
80
|
+
return;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
async function writeCache(file, data) {
|
|
84
|
+
const tmp = `${file}.${process.pid}-${Math.random().toString(36).slice(2)}.tmp`;
|
|
85
|
+
try {
|
|
86
|
+
await (0, node_fs_promises.writeFile)(tmp, data);
|
|
87
|
+
await (0, node_fs_promises.rename)(tmp, file);
|
|
88
|
+
} catch {
|
|
89
|
+
await (0, node_fs_promises.rm)(tmp, { force: true });
|
|
90
|
+
}
|
|
91
|
+
}
|
|
92
|
+
const inflight = /* @__PURE__ */ new Map();
|
|
93
|
+
/**
|
|
94
|
+
* Everything besides the config and the source that decides the encoded bytes: this package
|
|
95
|
+
* (transform behavior), and sharp with every codec it bundles (`sharp.versions` lists libvips,
|
|
96
|
+
* mozjpeg, libwebp, aom, …). Upgrading any of them must not serve images encoded by the old one.
|
|
97
|
+
*/
|
|
98
|
+
const ENGINE = JSON.stringify({
|
|
99
|
+
package: version,
|
|
100
|
+
sharp: sharp.default.versions
|
|
101
|
+
});
|
|
102
|
+
function cacheKey(config, sourceHash, removeMetadata, engine = ENGINE) {
|
|
103
|
+
return hash([
|
|
104
|
+
JSON.stringify(config),
|
|
105
|
+
sourceHash,
|
|
106
|
+
String(removeMetadata),
|
|
107
|
+
engine
|
|
108
|
+
]);
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Runs one resolved config through imagetools-core, memoized in-process and on disk. Both the
|
|
112
|
+
* module loader (needs dimensions) and the asset loader (needs bytes) call this. The cache key
|
|
113
|
+
* covers the source, the config, the options that change the output and the engine versions, so
|
|
114
|
+
* editing any of them never hits a stale entry.
|
|
115
|
+
*/
|
|
116
|
+
function processImage(args) {
|
|
117
|
+
const engine = args.configHash ? `${ENGINE}|config:${args.configHash}` : ENGINE;
|
|
118
|
+
const id = cacheKey(args.config, args.sourceHash, args.removeMetadata, engine);
|
|
119
|
+
let p = inflight.get(id);
|
|
120
|
+
if (!p) {
|
|
121
|
+
p = run(id, args);
|
|
122
|
+
inflight.set(id, p);
|
|
123
|
+
p.finally(() => inflight.delete(id)).catch(() => {});
|
|
124
|
+
}
|
|
125
|
+
return p;
|
|
126
|
+
}
|
|
127
|
+
async function run(id, args) {
|
|
128
|
+
const file = args.cacheDir === void 0 ? void 0 : node_path.default.join(args.cacheDir, id);
|
|
129
|
+
let data = file === void 0 ? void 0 : await readCached(file);
|
|
130
|
+
let transforms = {};
|
|
131
|
+
if (!data) {
|
|
132
|
+
const { transforms: steps } = (0, imagetools_core.generateTransforms)(args.config, args.factories, args.searchParams, args.logger);
|
|
133
|
+
const animation = await animationOf(args.source, args.config);
|
|
134
|
+
const input = (0, sharp.default)(args.source, { animated: animation.kept });
|
|
135
|
+
const res = await (0, imagetools_core.applyTransforms)(animation.kept ? [frameSize(animation.frameHeight), ...steps] : steps, input, args.removeMetadata);
|
|
136
|
+
data = (await res.image.toBuffer({ resolveWithObject: true })).data;
|
|
137
|
+
transforms = res.metadata.transforms;
|
|
138
|
+
if (file !== void 0) await writeCache(file, data);
|
|
139
|
+
}
|
|
140
|
+
const meta = await (0, sharp.default)(data).metadata();
|
|
141
|
+
const format = args.config["format"] ?? transforms.format ?? meta.format;
|
|
142
|
+
if (format !== void 0) transforms.format = format;
|
|
143
|
+
return {
|
|
144
|
+
id,
|
|
145
|
+
data,
|
|
146
|
+
meta,
|
|
147
|
+
transforms
|
|
148
|
+
};
|
|
149
|
+
}
|
|
150
|
+
const NO_CONFIG = {
|
|
151
|
+
config: {},
|
|
152
|
+
hash: "",
|
|
153
|
+
factories: imagetools_core.builtins
|
|
154
|
+
};
|
|
155
|
+
const loadedConfigs = /* @__PURE__ */ new Map();
|
|
156
|
+
/**
|
|
157
|
+
* Imports the `configFile` module, if any. Three caches could otherwise serve an outdated config:
|
|
158
|
+
*
|
|
159
|
+
* - Turbopack, which reruns a loader only when its inputs change: the file is registered as a
|
|
160
|
+
* dependency of every module that uses it.
|
|
161
|
+
* - Node's module cache, which returns the first import forever: the file is imported with its
|
|
162
|
+
* content hash in the URL, so an edit loads a new module.
|
|
163
|
+
* - The disk cache: the hash is part of every cache key (see processImage).
|
|
164
|
+
*/
|
|
165
|
+
async function loadConfig(ctx, options) {
|
|
166
|
+
if (!options.configFile) return NO_CONFIG;
|
|
167
|
+
const file = node_path.default.resolve(ctx.rootContext ?? process.cwd(), options.configFile);
|
|
168
|
+
ctx.addDependency?.(file);
|
|
169
|
+
const contentHash = hash([await (0, node_fs_promises.readFile)(file).catch(() => {
|
|
170
|
+
throw new Error(`next-imagetools: configFile not found at ${file}`);
|
|
171
|
+
})]);
|
|
172
|
+
let loaded = loadedConfigs.get(contentHash);
|
|
173
|
+
if (!loaded) {
|
|
174
|
+
loaded = import(`${(0, node_url.pathToFileURL)(file).href}?v=${contentHash}`).then((mod) => {
|
|
175
|
+
const config = mod.default ?? mod;
|
|
176
|
+
return {
|
|
177
|
+
config,
|
|
178
|
+
hash: contentHash,
|
|
179
|
+
factories: config.extendTransforms?.(imagetools_core.builtins) ?? imagetools_core.builtins
|
|
180
|
+
};
|
|
181
|
+
});
|
|
182
|
+
loadedConfigs.set(contentHash, loaded);
|
|
183
|
+
}
|
|
184
|
+
return loaded;
|
|
185
|
+
}
|
|
186
|
+
/**
|
|
187
|
+
* Runs a loader, prefixing any error with the file and query it was processing: in a large app,
|
|
188
|
+
* "Expected positive integer for width" alone doesn't say which of hundreds of imports to fix.
|
|
189
|
+
*/
|
|
190
|
+
async function withContext(ctx, task) {
|
|
191
|
+
try {
|
|
192
|
+
return await task();
|
|
193
|
+
} catch (error) {
|
|
194
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
195
|
+
throw new Error(`next-imagetools: ${where(ctx)}: ${message}`, { cause: error });
|
|
196
|
+
}
|
|
197
|
+
}
|
|
198
|
+
/** The import being processed, as the user wrote it: app-relative path plus query. */
|
|
199
|
+
function where(ctx) {
|
|
200
|
+
return `${node_path.default.relative(ctx.rootContext ?? process.cwd(), ctx.resourcePath).split(node_path.default.sep).join("/")}${ctx.resourceQuery}`;
|
|
201
|
+
}
|
|
202
|
+
/**
|
|
203
|
+
* Emits a build warning about the current import. Turbopack prints a warning's name and stack, so
|
|
204
|
+
* the stack is replaced by the message: it's about the user's import, not our code.
|
|
205
|
+
*/
|
|
206
|
+
function warn(ctx, message) {
|
|
207
|
+
const warning = /* @__PURE__ */ new Error(`${where(ctx)}: ${message}`);
|
|
208
|
+
warning.name = "next-imagetools";
|
|
209
|
+
warning.stack = `${warning.name}: ${warning.message}`;
|
|
210
|
+
ctx.emitWarning?.(warning);
|
|
211
|
+
}
|
|
212
|
+
/** Output formats sharp can encode with several frames. */
|
|
213
|
+
const ANIMATED_FORMATS = /* @__PURE__ */ new Set(["gif", "webp"]);
|
|
214
|
+
/**
|
|
215
|
+
* Whether a source is an animation. Several pages alone don't make one: a multi-page TIFF has them
|
|
216
|
+
* too, and must not turn into an animated WebP. Only animations carry frame delays.
|
|
217
|
+
*/
|
|
218
|
+
const isAnimated = (meta) => (meta.pages ?? 1) > 1 && meta.delay !== void 0;
|
|
219
|
+
/**
|
|
220
|
+
* Whether an image keeps its animation — an animated source, and an output that can hold the frames
|
|
221
|
+
* — and the height of one frame.
|
|
222
|
+
*/
|
|
223
|
+
async function animationOf(source, config) {
|
|
224
|
+
const meta = await (0, sharp.default)(source).metadata();
|
|
225
|
+
const format = config["format"] ?? meta.format;
|
|
226
|
+
return {
|
|
227
|
+
kept: isAnimated(meta) && format !== void 0 && ANIMATED_FORMATS.has(format),
|
|
228
|
+
frameHeight: meta.height
|
|
229
|
+
};
|
|
230
|
+
}
|
|
231
|
+
/**
|
|
232
|
+
* An animated image is read as one tall strip of frames, so the pipeline would start from the
|
|
233
|
+
* strip's height and resize every frame to the wrong aspect ratio. This first step puts one frame's
|
|
234
|
+
* height in place; sharp then applies the resize to each frame.
|
|
235
|
+
*/
|
|
236
|
+
const frameSize = (frameHeight) => (state, image) => {
|
|
237
|
+
state.info.height = frameHeight;
|
|
238
|
+
state.info.autoOriented.height = frameHeight;
|
|
239
|
+
return image;
|
|
240
|
+
};
|
|
241
|
+
Object.defineProperty(exports, "ANIMATED_FORMATS", {
|
|
242
|
+
enumerable: true,
|
|
243
|
+
get: function() {
|
|
244
|
+
return ANIMATED_FORMATS;
|
|
245
|
+
}
|
|
246
|
+
});
|
|
247
|
+
Object.defineProperty(exports, "__toESM", {
|
|
248
|
+
enumerable: true,
|
|
249
|
+
get: function() {
|
|
250
|
+
return __toESM;
|
|
251
|
+
}
|
|
252
|
+
});
|
|
253
|
+
Object.defineProperty(exports, "hash", {
|
|
254
|
+
enumerable: true,
|
|
255
|
+
get: function() {
|
|
256
|
+
return hash;
|
|
257
|
+
}
|
|
258
|
+
});
|
|
259
|
+
Object.defineProperty(exports, "isAnimated", {
|
|
260
|
+
enumerable: true,
|
|
261
|
+
get: function() {
|
|
262
|
+
return isAnimated;
|
|
263
|
+
}
|
|
264
|
+
});
|
|
265
|
+
Object.defineProperty(exports, "loadConfig", {
|
|
266
|
+
enumerable: true,
|
|
267
|
+
get: function() {
|
|
268
|
+
return loadConfig;
|
|
269
|
+
}
|
|
270
|
+
});
|
|
271
|
+
Object.defineProperty(exports, "prepareCache", {
|
|
272
|
+
enumerable: true,
|
|
273
|
+
get: function() {
|
|
274
|
+
return prepareCache;
|
|
275
|
+
}
|
|
276
|
+
});
|
|
277
|
+
Object.defineProperty(exports, "processImage", {
|
|
278
|
+
enumerable: true,
|
|
279
|
+
get: function() {
|
|
280
|
+
return processImage;
|
|
281
|
+
}
|
|
282
|
+
});
|
|
283
|
+
Object.defineProperty(exports, "toParams", {
|
|
284
|
+
enumerable: true,
|
|
285
|
+
get: function() {
|
|
286
|
+
return toParams;
|
|
287
|
+
}
|
|
288
|
+
});
|
|
289
|
+
Object.defineProperty(exports, "warn", {
|
|
290
|
+
enumerable: true,
|
|
291
|
+
get: function() {
|
|
292
|
+
return warn;
|
|
293
|
+
}
|
|
294
|
+
});
|
|
295
|
+
Object.defineProperty(exports, "withContext", {
|
|
296
|
+
enumerable: true,
|
|
297
|
+
get: function() {
|
|
298
|
+
return withContext;
|
|
299
|
+
}
|
|
300
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,111 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "next-imagetools",
|
|
3
|
-
"version": "0.0.0
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.0.0",
|
|
4
|
+
"description": "Build-time image transforms for Next.js: import './a.jpg?w=400;800&format=webp&as=srcset' and get optimized files, no image server needed.",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"avif",
|
|
7
|
+
"imagetools",
|
|
8
|
+
"next",
|
|
9
|
+
"nextjs",
|
|
10
|
+
"responsive-images",
|
|
11
|
+
"sharp",
|
|
12
|
+
"srcset",
|
|
13
|
+
"static-export",
|
|
14
|
+
"turbopack",
|
|
15
|
+
"webp"
|
|
16
|
+
],
|
|
17
|
+
"homepage": "https://github.com/awdr74100/next-imagetools#readme",
|
|
18
|
+
"bugs": {
|
|
19
|
+
"url": "https://github.com/awdr74100/next-imagetools/issues"
|
|
20
|
+
},
|
|
21
|
+
"license": "MIT",
|
|
22
|
+
"author": "Roya <a78945612385238@gmail.com>",
|
|
23
|
+
"repository": {
|
|
24
|
+
"type": "git",
|
|
25
|
+
"url": "git+https://github.com/awdr74100/next-imagetools.git"
|
|
26
|
+
},
|
|
27
|
+
"files": [
|
|
28
|
+
"dist",
|
|
29
|
+
"client.d.ts"
|
|
30
|
+
],
|
|
31
|
+
"type": "module",
|
|
32
|
+
"sideEffects": false,
|
|
33
|
+
"main": "./dist/index.cjs",
|
|
34
|
+
"module": "./dist/index.mjs",
|
|
35
|
+
"types": "./dist/index.d.mts",
|
|
36
|
+
"exports": {
|
|
37
|
+
".": {
|
|
38
|
+
"types": {
|
|
39
|
+
"import": "./dist/index.d.mts",
|
|
40
|
+
"require": "./dist/index.d.cts"
|
|
41
|
+
},
|
|
42
|
+
"import": "./dist/index.mjs",
|
|
43
|
+
"require": "./dist/index.cjs"
|
|
44
|
+
},
|
|
45
|
+
"./config": {
|
|
46
|
+
"types": {
|
|
47
|
+
"import": "./dist/config.d.mts",
|
|
48
|
+
"require": "./dist/config.d.cts"
|
|
49
|
+
},
|
|
50
|
+
"import": "./dist/config.mjs",
|
|
51
|
+
"require": "./dist/config.cjs"
|
|
52
|
+
},
|
|
53
|
+
"./core": {
|
|
54
|
+
"types": {
|
|
55
|
+
"import": "./dist/core.d.mts",
|
|
56
|
+
"require": "./dist/core.d.cts"
|
|
57
|
+
},
|
|
58
|
+
"import": "./dist/core.mjs",
|
|
59
|
+
"require": "./dist/core.cjs"
|
|
60
|
+
},
|
|
61
|
+
"./loader": "./dist/loader.cjs",
|
|
62
|
+
"./asset-loader": "./dist/asset-loader.cjs",
|
|
63
|
+
"./client": {
|
|
64
|
+
"types": "./client.d.ts"
|
|
65
|
+
},
|
|
66
|
+
"./package.json": "./package.json"
|
|
67
|
+
},
|
|
68
|
+
"dependencies": {
|
|
69
|
+
"imagetools-core": "^12.0.0",
|
|
70
|
+
"picomatch": "^4.0.7",
|
|
71
|
+
"sharp": "^0.35.5"
|
|
72
|
+
},
|
|
73
|
+
"devDependencies": {
|
|
74
|
+
"@types/node": "^26.6.6",
|
|
75
|
+
"@types/picomatch": "^4.0.3",
|
|
76
|
+
"changelogen": "^0.6.2",
|
|
77
|
+
"knip": "^6.44.2",
|
|
78
|
+
"next": "^16.4.5",
|
|
79
|
+
"oxfmt": "^0.78.0",
|
|
80
|
+
"oxlint": "^1.93.0",
|
|
81
|
+
"playwright": "^1.65.0",
|
|
82
|
+
"publint": "^0.3.25",
|
|
83
|
+
"tsdown": "^0.23.7",
|
|
84
|
+
"typescript": "^6.0.3",
|
|
85
|
+
"vitest": "^5.1.0"
|
|
86
|
+
},
|
|
87
|
+
"peerDependencies": {
|
|
88
|
+
"next": ">=16.2.0"
|
|
89
|
+
},
|
|
90
|
+
"engines": {
|
|
91
|
+
"node": ">=22.12.0"
|
|
92
|
+
},
|
|
93
|
+
"scripts": {
|
|
94
|
+
"build": "tsdown",
|
|
95
|
+
"build:watch": "tsdown --watch",
|
|
96
|
+
"check": "pnpm typecheck && pnpm lint && pnpm lint:english && pnpm format:check && pnpm knip",
|
|
97
|
+
"format": "oxfmt .",
|
|
98
|
+
"format:check": "oxfmt --check .",
|
|
99
|
+
"knip": "knip",
|
|
100
|
+
"knip:fix": "knip --fix",
|
|
101
|
+
"lint": "oxlint --deny-warnings .",
|
|
102
|
+
"lint:english": "node scripts/check-english.mjs",
|
|
103
|
+
"lint:fix": "oxlint --fix .",
|
|
104
|
+
"playground": "pnpm build && pnpm -C playground run dev",
|
|
105
|
+
"release": "node scripts/release.mjs",
|
|
106
|
+
"test": "vitest run",
|
|
107
|
+
"test:e2e": "vitest run --project e2e",
|
|
108
|
+
"test:unit": "vitest run --project unit",
|
|
109
|
+
"typecheck": "pnpm -r run typecheck && tsc --noEmit -p tsconfig.json"
|
|
110
|
+
}
|
|
6
111
|
}
|