sharp 0.32.6 → 0.33.4

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/lib/is.js CHANGED
@@ -137,19 +137,33 @@ const invalidParameterError = function (name, expected, actual) {
137
137
  );
138
138
  };
139
139
 
140
+ /**
141
+ * Ensures an Error from C++ contains a JS stack.
142
+ *
143
+ * @param {Error} native - Error with message from C++.
144
+ * @param {Error} context - Error with stack from JS.
145
+ * @returns {Error} Error with message and stack.
146
+ * @private
147
+ */
148
+ const nativeError = function (native, context) {
149
+ context.message = native.message;
150
+ return context;
151
+ };
152
+
140
153
  module.exports = {
141
- defined: defined,
142
- object: object,
143
- plainObject: plainObject,
144
- fn: fn,
145
- bool: bool,
146
- buffer: buffer,
147
- typedArray: typedArray,
148
- arrayBuffer: arrayBuffer,
149
- string: string,
150
- number: number,
151
- integer: integer,
152
- inRange: inRange,
153
- inArray: inArray,
154
- invalidParameterError: invalidParameterError
154
+ defined,
155
+ object,
156
+ plainObject,
157
+ fn,
158
+ bool,
159
+ buffer,
160
+ typedArray,
161
+ arrayBuffer,
162
+ string,
163
+ number,
164
+ integer,
165
+ inRange,
166
+ inArray,
167
+ invalidParameterError,
168
+ nativeError
155
169
  };
package/lib/libvips.js CHANGED
@@ -3,61 +3,103 @@
3
3
 
4
4
  'use strict';
5
5
 
6
- const fs = require('fs');
7
- const os = require('os');
8
- const path = require('path');
9
- const spawnSync = require('child_process').spawnSync;
6
+ const { spawnSync } = require('node:child_process');
7
+ const { createHash } = require('node:crypto');
10
8
  const semverCoerce = require('semver/functions/coerce');
11
9
  const semverGreaterThanOrEqualTo = require('semver/functions/gte');
10
+ const semverSatisfies = require('semver/functions/satisfies');
11
+ const detectLibc = require('detect-libc');
12
12
 
13
- const platform = require('./platform');
14
- const { config } = require('../package.json');
13
+ const { engines, optionalDependencies } = require('../package.json');
15
14
 
16
- const env = process.env;
17
- const minimumLibvipsVersionLabelled = env.npm_package_config_libvips || /* istanbul ignore next */
18
- config.libvips;
15
+ const minimumLibvipsVersionLabelled = process.env.npm_package_config_libvips || /* istanbul ignore next */
16
+ engines.libvips;
19
17
  const minimumLibvipsVersion = semverCoerce(minimumLibvipsVersionLabelled).version;
20
18
 
19
+ const prebuiltPlatforms = [
20
+ 'darwin-arm64', 'darwin-x64',
21
+ 'linux-arm', 'linux-arm64', 'linux-s390x', 'linux-x64',
22
+ 'linuxmusl-arm64', 'linuxmusl-x64',
23
+ 'win32-ia32', 'win32-x64'
24
+ ];
25
+
21
26
  const spawnSyncOptions = {
22
27
  encoding: 'utf8',
23
28
  shell: true
24
29
  };
25
30
 
26
- const vendorPath = path.join(__dirname, '..', 'vendor', minimumLibvipsVersion, platform());
31
+ const log = (item) => {
32
+ if (item instanceof Error) {
33
+ console.error(`sharp: Installation error: ${item.message}`);
34
+ } else {
35
+ console.log(`sharp: ${item}`);
36
+ }
37
+ };
38
+
39
+ /* istanbul ignore next */
40
+ const runtimeLibc = () => detectLibc.isNonGlibcLinuxSync() ? detectLibc.familySync() : '';
41
+
42
+ const runtimePlatformArch = () => `${process.platform}${runtimeLibc()}-${process.arch}`;
27
43
 
28
- const mkdirSync = function (dirPath) {
44
+ /* istanbul ignore next */
45
+ const buildPlatformArch = () => {
46
+ if (isEmscripten()) {
47
+ return 'wasm32';
48
+ }
49
+ /* eslint camelcase: ["error", { allow: ["^npm_config_"] }] */
50
+ const { npm_config_arch, npm_config_platform, npm_config_libc } = process.env;
51
+ const libc = typeof npm_config_libc === 'string' ? npm_config_libc : runtimeLibc();
52
+ return `${npm_config_platform || process.platform}${libc}-${npm_config_arch || process.arch}`;
53
+ };
54
+
55
+ const buildSharpLibvipsIncludeDir = () => {
29
56
  try {
30
- fs.mkdirSync(dirPath, { recursive: true });
31
- } catch (err) {
32
- /* istanbul ignore next */
33
- if (err.code !== 'EEXIST') {
34
- throw err;
35
- }
57
+ return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/include`);
58
+ } catch {
59
+ try {
60
+ return require('@img/sharp-libvips-dev/include');
61
+ } catch {}
36
62
  }
63
+ /* istanbul ignore next */
64
+ return '';
37
65
  };
38
66
 
39
- const cachePath = function () {
40
- const npmCachePath = env.npm_config_cache || /* istanbul ignore next */
41
- (env.APPDATA ? path.join(env.APPDATA, 'npm-cache') : path.join(os.homedir(), '.npm'));
42
- mkdirSync(npmCachePath);
43
- const libvipsCachePath = path.join(npmCachePath, '_libvips');
44
- mkdirSync(libvipsCachePath);
45
- return libvipsCachePath;
67
+ const buildSharpLibvipsCPlusPlusDir = () => {
68
+ try {
69
+ return require('@img/sharp-libvips-dev/cplusplus');
70
+ } catch {}
71
+ /* istanbul ignore next */
72
+ return '';
46
73
  };
47
74
 
48
- const integrity = function (platformAndArch) {
49
- return env[`npm_package_config_integrity_${platformAndArch.replace('-', '_')}`] || config.integrity[platformAndArch];
75
+ const buildSharpLibvipsLibDir = () => {
76
+ try {
77
+ return require(`@img/sharp-libvips-dev-${buildPlatformArch()}/lib`);
78
+ } catch {
79
+ try {
80
+ return require(`@img/sharp-libvips-${buildPlatformArch()}/lib`);
81
+ } catch {}
82
+ }
83
+ /* istanbul ignore next */
84
+ return '';
50
85
  };
51
86
 
52
- const log = function (item) {
53
- if (item instanceof Error) {
54
- console.error(`sharp: Installation error: ${item.message}`);
55
- } else {
56
- console.log(`sharp: ${item}`);
87
+ const isUnsupportedNodeRuntime = () => {
88
+ /* istanbul ignore next */
89
+ if (process.release?.name === 'node' && process.versions) {
90
+ if (!semverSatisfies(process.versions.node, engines.node)) {
91
+ return { found: process.versions.node, expected: engines.node };
92
+ }
57
93
  }
58
94
  };
59
95
 
60
- const isRosetta = function () {
96
+ /* istanbul ignore next */
97
+ const isEmscripten = () => {
98
+ const { CC } = process.env;
99
+ return Boolean(CC && CC.endsWith('/emcc'));
100
+ };
101
+
102
+ const isRosetta = () => {
61
103
  /* istanbul ignore next */
62
104
  if (process.platform === 'darwin' && process.arch === 'x64') {
63
105
  const translated = spawnSync('sysctl sysctl.proc_translated', spawnSyncOptions).stdout;
@@ -66,12 +108,30 @@ const isRosetta = function () {
66
108
  return false;
67
109
  };
68
110
 
69
- const globalLibvipsVersion = function () {
111
+ const sha512 = (s) => createHash('sha512').update(s).digest('hex');
112
+
113
+ const yarnLocator = () => {
114
+ try {
115
+ const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
116
+ const npmVersion = semverCoerce(optionalDependencies[`@img/sharp-libvips-${buildPlatformArch()}`]).version;
117
+ return sha512(`${identHash}npm:${npmVersion}`).slice(0, 10);
118
+ } catch {}
119
+ return '';
120
+ };
121
+
122
+ /* istanbul ignore next */
123
+ const spawnRebuild = () =>
124
+ spawnSync(`node-gyp rebuild --directory=src ${isEmscripten() ? '--nodedir=emscripten' : ''}`, {
125
+ ...spawnSyncOptions,
126
+ stdio: 'inherit'
127
+ }).status;
128
+
129
+ const globalLibvipsVersion = () => {
70
130
  if (process.platform !== 'win32') {
71
131
  const globalLibvipsVersion = spawnSync('pkg-config --modversion vips-cpp', {
72
132
  ...spawnSyncOptions,
73
133
  env: {
74
- ...env,
134
+ ...process.env,
75
135
  PKG_CONFIG_PATH: pkgConfigPath()
76
136
  }
77
137
  }).stdout;
@@ -82,17 +142,8 @@ const globalLibvipsVersion = function () {
82
142
  }
83
143
  };
84
144
 
85
- const hasVendoredLibvips = function () {
86
- return fs.existsSync(vendorPath);
87
- };
88
-
89
145
  /* istanbul ignore next */
90
- const removeVendoredLibvips = function () {
91
- fs.rmSync(vendorPath, { recursive: true, maxRetries: 3, force: true });
92
- };
93
-
94
- /* istanbul ignore next */
95
- const pkgConfigPath = function () {
146
+ const pkgConfigPath = () => {
96
147
  if (process.platform !== 'win32') {
97
148
  const brewPkgConfigPath = spawnSync(
98
149
  'which brew >/dev/null 2>&1 && brew environment --plain | grep PKG_CONFIG_LIBDIR | cut -d" " -f2',
@@ -100,7 +151,7 @@ const pkgConfigPath = function () {
100
151
  ).stdout || '';
101
152
  return [
102
153
  brewPkgConfigPath.trim(),
103
- env.PKG_CONFIG_PATH,
154
+ process.env.PKG_CONFIG_PATH,
104
155
  '/usr/local/lib/pkgconfig',
105
156
  '/usr/lib/pkgconfig',
106
157
  '/usr/local/libdata/pkgconfig',
@@ -111,14 +162,21 @@ const pkgConfigPath = function () {
111
162
  }
112
163
  };
113
164
 
114
- const useGlobalLibvips = function () {
115
- if (Boolean(env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
116
- return false;
165
+ const skipSearch = (status, reason) => {
166
+ log(`Detected ${reason}, skipping search for globally-installed libvips`);
167
+ return status;
168
+ };
169
+
170
+ const useGlobalLibvips = () => {
171
+ if (Boolean(process.env.SHARP_IGNORE_GLOBAL_LIBVIPS) === true) {
172
+ return skipSearch(false, 'SHARP_IGNORE_GLOBAL_LIBVIPS');
173
+ }
174
+ if (Boolean(process.env.SHARP_FORCE_GLOBAL_LIBVIPS) === true) {
175
+ return skipSearch(true, 'SHARP_FORCE_GLOBAL_LIBVIPS');
117
176
  }
118
177
  /* istanbul ignore next */
119
178
  if (isRosetta()) {
120
- log('Detected Rosetta, skipping search for globally-installed libvips');
121
- return false;
179
+ return skipSearch(false, 'Rosetta');
122
180
  }
123
181
  const globalVipsVersion = globalLibvipsVersion();
124
182
  return !!globalVipsVersion && /* istanbul ignore next */
@@ -127,14 +185,17 @@ const useGlobalLibvips = function () {
127
185
 
128
186
  module.exports = {
129
187
  minimumLibvipsVersion,
130
- minimumLibvipsVersionLabelled,
131
- cachePath,
132
- integrity,
188
+ prebuiltPlatforms,
189
+ buildPlatformArch,
190
+ buildSharpLibvipsIncludeDir,
191
+ buildSharpLibvipsCPlusPlusDir,
192
+ buildSharpLibvipsLibDir,
193
+ isUnsupportedNodeRuntime,
194
+ runtimePlatformArch,
133
195
  log,
196
+ yarnLocator,
197
+ spawnRebuild,
134
198
  globalLibvipsVersion,
135
- hasVendoredLibvips,
136
- removeVendoredLibvips,
137
199
  pkgConfigPath,
138
- useGlobalLibvips,
139
- mkdirSync
200
+ useGlobalLibvips
140
201
  };
package/lib/operation.js CHANGED
@@ -24,6 +24,8 @@ const is = require('./is');
24
24
  * Only one rotation can occur per pipeline.
25
25
  * Previous calls to `rotate` in the same pipeline will be ignored.
26
26
  *
27
+ * Multi-page images can only be rotated by 180 degrees.
28
+ *
27
29
  * Method order is important when rotating, resizing and/or extracting regions,
28
30
  * for example `.rotate(x).extract(y)` will produce a different result to `.extract(y).rotate(x)`.
29
31
  *