@loaders.gl/core 4.0.0-alpha.6 → 4.0.0-alpha.7

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.
Files changed (71) hide show
  1. package/dist/dist.min.js +97 -65
  2. package/dist/es5/lib/api/load.js.map +1 -1
  3. package/dist/es5/lib/api/parse-in-batches.js +15 -14
  4. package/dist/es5/lib/api/parse-in-batches.js.map +1 -1
  5. package/dist/es5/lib/api/parse-sync.js +3 -4
  6. package/dist/es5/lib/api/parse-sync.js.map +1 -1
  7. package/dist/es5/lib/api/parse.js +3 -3
  8. package/dist/es5/lib/api/parse.js.map +1 -1
  9. package/dist/es5/lib/api/select-loader.js +6 -7
  10. package/dist/es5/lib/api/select-loader.js.map +1 -1
  11. package/dist/es5/lib/init.js +1 -1
  12. package/dist/es5/lib/loader-utils/loader-context.js +16 -8
  13. package/dist/es5/lib/loader-utils/loader-context.js.map +1 -1
  14. package/dist/es5/lib/utils/resource-utils.js +31 -27
  15. package/dist/es5/lib/utils/resource-utils.js.map +1 -1
  16. package/dist/es5/lib/utils/response-utils.js +6 -5
  17. package/dist/es5/lib/utils/response-utils.js.map +1 -1
  18. package/dist/es5/lib/utils/url-utils.js +16 -0
  19. package/dist/es5/lib/utils/url-utils.js.map +1 -0
  20. package/dist/es5/null-loader.js +1 -1
  21. package/dist/esm/lib/api/load.js.map +1 -1
  22. package/dist/esm/lib/api/parse-in-batches.js +6 -7
  23. package/dist/esm/lib/api/parse-in-batches.js.map +1 -1
  24. package/dist/esm/lib/api/parse-sync.js +4 -6
  25. package/dist/esm/lib/api/parse-sync.js.map +1 -1
  26. package/dist/esm/lib/api/parse.js +3 -5
  27. package/dist/esm/lib/api/parse.js.map +1 -1
  28. package/dist/esm/lib/api/select-loader.js +7 -10
  29. package/dist/esm/lib/api/select-loader.js.map +1 -1
  30. package/dist/esm/lib/init.js +1 -1
  31. package/dist/esm/lib/loader-utils/loader-context.js +16 -8
  32. package/dist/esm/lib/loader-utils/loader-context.js.map +1 -1
  33. package/dist/esm/lib/utils/resource-utils.js +29 -26
  34. package/dist/esm/lib/utils/resource-utils.js.map +1 -1
  35. package/dist/esm/lib/utils/response-utils.js +3 -5
  36. package/dist/esm/lib/utils/response-utils.js.map +1 -1
  37. package/dist/esm/lib/utils/url-utils.js +9 -0
  38. package/dist/esm/lib/utils/url-utils.js.map +1 -0
  39. package/dist/esm/null-loader.js +1 -1
  40. package/dist/lib/api/load.d.ts +2 -1
  41. package/dist/lib/api/load.d.ts.map +1 -1
  42. package/dist/lib/api/parse-in-batches.d.ts.map +1 -1
  43. package/dist/lib/api/parse-in-batches.js +4 -7
  44. package/dist/lib/api/parse-sync.d.ts.map +1 -1
  45. package/dist/lib/api/parse-sync.js +3 -3
  46. package/dist/lib/api/parse.js +2 -2
  47. package/dist/lib/api/select-loader.d.ts.map +1 -1
  48. package/dist/lib/api/select-loader.js +6 -3
  49. package/dist/lib/loader-utils/loader-context.d.ts +1 -1
  50. package/dist/lib/loader-utils/loader-context.d.ts.map +1 -1
  51. package/dist/lib/loader-utils/loader-context.js +17 -7
  52. package/dist/lib/utils/resource-utils.d.ts +17 -8
  53. package/dist/lib/utils/resource-utils.d.ts.map +1 -1
  54. package/dist/lib/utils/resource-utils.js +46 -34
  55. package/dist/lib/utils/response-utils.d.ts.map +1 -1
  56. package/dist/lib/utils/response-utils.js +2 -1
  57. package/dist/lib/utils/url-utils.d.ts +3 -0
  58. package/dist/lib/utils/url-utils.d.ts.map +1 -0
  59. package/dist/lib/utils/url-utils.js +14 -0
  60. package/dist/null-worker-node.js +234 -0
  61. package/dist/null-worker.js +1 -1
  62. package/package.json +7 -6
  63. package/src/lib/api/load.ts +1 -1
  64. package/src/lib/api/parse-in-batches.ts +8 -9
  65. package/src/lib/api/parse-sync.ts +8 -4
  66. package/src/lib/api/parse.ts +3 -3
  67. package/src/lib/api/select-loader.ts +7 -4
  68. package/src/lib/loader-utils/loader-context.ts +19 -8
  69. package/src/lib/utils/resource-utils.ts +54 -34
  70. package/src/lib/utils/response-utils.ts +3 -2
  71. package/src/lib/utils/url-utils.ts +12 -0
@@ -0,0 +1,234 @@
1
+ var __defProp = Object.defineProperty;
2
+ var __defProps = Object.defineProperties;
3
+ var __getOwnPropDescs = Object.getOwnPropertyDescriptors;
4
+ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __propIsEnum = Object.prototype.propertyIsEnumerable;
7
+ var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value;
8
+ var __spreadValues = (a, b) => {
9
+ for (var prop in b || (b = {}))
10
+ if (__hasOwnProp.call(b, prop))
11
+ __defNormalProp(a, prop, b[prop]);
12
+ if (__getOwnPropSymbols)
13
+ for (var prop of __getOwnPropSymbols(b)) {
14
+ if (__propIsEnum.call(b, prop))
15
+ __defNormalProp(a, prop, b[prop]);
16
+ }
17
+ return a;
18
+ };
19
+ var __spreadProps = (a, b) => __defProps(a, __getOwnPropDescs(b));
20
+
21
+ // ../worker-utils/src/lib/worker-utils/get-transfer-list.ts
22
+ function getTransferList(object, recursive = true, transfers) {
23
+ const transfersSet = transfers || new Set();
24
+ if (!object) {
25
+ } else if (isTransferable(object)) {
26
+ transfersSet.add(object);
27
+ } else if (isTransferable(object.buffer)) {
28
+ transfersSet.add(object.buffer);
29
+ } else if (ArrayBuffer.isView(object)) {
30
+ } else if (recursive && typeof object === "object") {
31
+ for (const key in object) {
32
+ getTransferList(object[key], recursive, transfersSet);
33
+ }
34
+ }
35
+ return transfers === void 0 ? Array.from(transfersSet) : [];
36
+ }
37
+ function isTransferable(object) {
38
+ if (!object) {
39
+ return false;
40
+ }
41
+ if (object instanceof ArrayBuffer) {
42
+ return true;
43
+ }
44
+ if (typeof MessagePort !== "undefined" && object instanceof MessagePort) {
45
+ return true;
46
+ }
47
+ if (typeof ImageBitmap !== "undefined" && object instanceof ImageBitmap) {
48
+ return true;
49
+ }
50
+ if (typeof OffscreenCanvas !== "undefined" && object instanceof OffscreenCanvas) {
51
+ return true;
52
+ }
53
+ return false;
54
+ }
55
+
56
+ // ../worker-utils/src/lib/worker-farm/worker-body.ts
57
+ function getParentPort() {
58
+ let parentPort;
59
+ try {
60
+ eval("globalThis.parentPort = require('worker_threads').parentPort");
61
+ parentPort = globalThis.parentPort;
62
+ } catch {
63
+ }
64
+ return parentPort;
65
+ }
66
+ var onMessageWrapperMap = new Map();
67
+ var WorkerBody = class {
68
+ static inWorkerThread() {
69
+ return typeof self !== "undefined" || Boolean(getParentPort());
70
+ }
71
+ static set onmessage(onMessage) {
72
+ function handleMessage(message) {
73
+ const parentPort3 = getParentPort();
74
+ const { type, payload } = parentPort3 ? message : message.data;
75
+ onMessage(type, payload);
76
+ }
77
+ const parentPort2 = getParentPort();
78
+ if (parentPort2) {
79
+ parentPort2.on("message", handleMessage);
80
+ parentPort2.on("exit", () => console.debug("Node worker closing"));
81
+ } else {
82
+ globalThis.onmessage = handleMessage;
83
+ }
84
+ }
85
+ static addEventListener(onMessage) {
86
+ let onMessageWrapper = onMessageWrapperMap.get(onMessage);
87
+ if (!onMessageWrapper) {
88
+ onMessageWrapper = (message) => {
89
+ if (!isKnownMessage(message)) {
90
+ return;
91
+ }
92
+ const parentPort3 = getParentPort();
93
+ const { type, payload } = parentPort3 ? message : message.data;
94
+ onMessage(type, payload);
95
+ };
96
+ }
97
+ const parentPort2 = getParentPort();
98
+ if (parentPort2) {
99
+ console.error("not implemented");
100
+ } else {
101
+ globalThis.addEventListener("message", onMessageWrapper);
102
+ }
103
+ }
104
+ static removeEventListener(onMessage) {
105
+ const onMessageWrapper = onMessageWrapperMap.get(onMessage);
106
+ onMessageWrapperMap.delete(onMessage);
107
+ const parentPort2 = getParentPort();
108
+ if (parentPort2) {
109
+ console.error("not implemented");
110
+ } else {
111
+ globalThis.removeEventListener("message", onMessageWrapper);
112
+ }
113
+ }
114
+ static postMessage(type, payload) {
115
+ const data = { source: "loaders.gl", type, payload };
116
+ const transferList = getTransferList(payload);
117
+ const parentPort2 = getParentPort();
118
+ if (parentPort2) {
119
+ parentPort2.postMessage(data, transferList);
120
+ } else {
121
+ globalThis.postMessage(data, transferList);
122
+ }
123
+ }
124
+ };
125
+ function isKnownMessage(message) {
126
+ const { type, data } = message;
127
+ return type === "message" && data && typeof data.source === "string" && data.source.startsWith("loaders.gl");
128
+ }
129
+
130
+ // ../loader-utils/src/lib/worker-loader-utils/create-loader-worker.ts
131
+ var requestId = 0;
132
+ function createLoaderWorker(loader) {
133
+ if (!WorkerBody.inWorkerThread()) {
134
+ return;
135
+ }
136
+ WorkerBody.onmessage = async (type, payload) => {
137
+ switch (type) {
138
+ case "process":
139
+ try {
140
+ const { input, options = {}, context = {} } = payload;
141
+ const result = await parseData({
142
+ loader,
143
+ arrayBuffer: input,
144
+ options,
145
+ context: __spreadProps(__spreadValues({}, context), {
146
+ parse: parseOnMainThread
147
+ })
148
+ });
149
+ WorkerBody.postMessage("done", { result });
150
+ } catch (error) {
151
+ const message = error instanceof Error ? error.message : "";
152
+ WorkerBody.postMessage("error", { error: message });
153
+ }
154
+ break;
155
+ default:
156
+ }
157
+ };
158
+ }
159
+ function parseOnMainThread(arrayBuffer, options) {
160
+ return new Promise((resolve, reject) => {
161
+ const id = requestId++;
162
+ const onMessage = (type, payload2) => {
163
+ if (payload2.id !== id) {
164
+ return;
165
+ }
166
+ switch (type) {
167
+ case "done":
168
+ WorkerBody.removeEventListener(onMessage);
169
+ resolve(payload2.result);
170
+ break;
171
+ case "error":
172
+ WorkerBody.removeEventListener(onMessage);
173
+ reject(payload2.error);
174
+ break;
175
+ default:
176
+ }
177
+ };
178
+ WorkerBody.addEventListener(onMessage);
179
+ const payload = { id, input: arrayBuffer, options };
180
+ WorkerBody.postMessage("process", payload);
181
+ });
182
+ }
183
+ async function parseData({ loader, arrayBuffer, options, context }) {
184
+ let data;
185
+ let parser;
186
+ if (loader.parseSync || loader.parse) {
187
+ data = arrayBuffer;
188
+ parser = loader.parseSync || loader.parse;
189
+ } else if (loader.parseTextSync) {
190
+ const textDecoder = new TextDecoder();
191
+ data = textDecoder.decode(arrayBuffer);
192
+ parser = loader.parseTextSync;
193
+ } else {
194
+ throw new Error(`Could not load data with ${loader.name} loader`);
195
+ }
196
+ options = __spreadProps(__spreadValues({}, options), {
197
+ modules: loader && loader.options && loader.options.modules || {},
198
+ worker: false
199
+ });
200
+ return await parser(data, __spreadValues({}, options), context, loader);
201
+ }
202
+
203
+ // src/null-loader.ts
204
+ var VERSION = true ? "4.0.0-alpha.7" : "latest";
205
+ function parseSync(arrayBuffer, options, context) {
206
+ if (!options.null.echoParameters)
207
+ return null;
208
+ context = context && JSON.parse(JSON.stringify(context));
209
+ return { arrayBuffer, options, context };
210
+ }
211
+ var NullLoader = {
212
+ name: "Null loader",
213
+ id: "null",
214
+ module: "core",
215
+ version: VERSION,
216
+ mimeTypes: ["application/x.empty"],
217
+ extensions: ["null"],
218
+ parse: async (arrayBuffer, options, context) => parseSync(arrayBuffer, options, context),
219
+ parseSync,
220
+ parseInBatches: async function* generator(asyncIterator, options, context) {
221
+ for await (const batch of asyncIterator) {
222
+ yield parseSync(batch, options, context);
223
+ }
224
+ },
225
+ tests: [() => false],
226
+ options: {
227
+ null: {
228
+ echoParameters: false
229
+ }
230
+ }
231
+ };
232
+
233
+ // src/workers/null-worker.ts
234
+ createLoaderWorker(NullLoader);
@@ -184,7 +184,7 @@
184
184
  }
185
185
 
186
186
  // src/null-loader.ts
187
- var VERSION = true ? "4.0.0-alpha.6" : "latest";
187
+ var VERSION = true ? "4.0.0-alpha.7" : "latest";
188
188
  function parseSync(arrayBuffer, options, context) {
189
189
  if (!options.null.echoParameters)
190
190
  return null;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@loaders.gl/core",
3
- "version": "4.0.0-alpha.6",
3
+ "version": "4.0.0-alpha.7",
4
4
  "description": "The core API for working with loaders.gl loaders and writers",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
@@ -36,15 +36,16 @@
36
36
  "README.md"
37
37
  ],
38
38
  "scripts": {
39
- "pre-build": "npm run build-bundle && npm run build-worker",
39
+ "pre-build": "npm run build-bundle && npm run build-worker && npm run build-worker-node",
40
40
  "build-bundle": "esbuild src/bundle.ts --bundle --outfile=dist/dist.min.js",
41
- "build-worker": "esbuild src/workers/null-worker.ts --bundle --outfile=dist/null-worker.js --define:__VERSION__=\\\"$npm_package_version\\\""
41
+ "build-worker": "esbuild src/workers/null-worker.ts --outfile=dist/null-worker.js --bundle --target=esnext --define:__VERSION__=\\\"$npm_package_version\\\"",
42
+ "build-worker-node": "esbuild src/workers/null-worker.ts --outfile=dist/null-worker-node.js --bundle --platform=node --target=node16 --define:__VERSION__=\\\"$npm_package_version\\\""
42
43
  },
43
44
  "dependencies": {
44
45
  "@babel/runtime": "^7.3.1",
45
- "@loaders.gl/loader-utils": "4.0.0-alpha.6",
46
- "@loaders.gl/worker-utils": "4.0.0-alpha.6",
46
+ "@loaders.gl/loader-utils": "4.0.0-alpha.7",
47
+ "@loaders.gl/worker-utils": "4.0.0-alpha.7",
47
48
  "@probe.gl/log": "^4.0.2"
48
49
  },
49
- "gitHead": "acc1985050dfaa0f1f0c066f8da5bce7454a046c"
50
+ "gitHead": "afb59c4d8e5d8ebb9c28f111cb0c96c5527d0ffd"
50
51
  }
@@ -26,7 +26,7 @@ export async function load<LoaderT extends Loader>(
26
26
  ): Promise<LoaderReturnType<LoaderT>>;
27
27
 
28
28
  export async function load<
29
- LoaderT extends Loader,
29
+ LoaderT extends Loader, // eslint-disable-line @typescript-eslint/no-unused-vars
30
30
  LoaderOptionsT extends LoaderOptions = LoaderOptions
31
31
  >(
32
32
  url: string | DataType,
@@ -11,7 +11,7 @@ import {isLoaderObject} from '../loader-utils/normalize-loader';
11
11
  import {normalizeOptions} from '../loader-utils/option-utils';
12
12
  import {getLoaderContext} from '../loader-utils/loader-context';
13
13
  import {getAsyncIterableFromData} from '../loader-utils/get-data';
14
- import {getResourceUrlAndType} from '../utils/resource-utils';
14
+ import {getResourceUrl} from '../utils/resource-utils';
15
15
  import {selectLoader} from './select-loader';
16
16
 
17
17
  // Ensure `parse` is available in context if loader falls back to `parse`
@@ -32,6 +32,8 @@ export async function parseInBatches(
32
32
  ): Promise<AsyncIterable<any>> {
33
33
  assert(!context || typeof context === 'object'); // parseInBatches no longer accepts final url
34
34
 
35
+ const loaderArray = Array.isArray(loaders) ? loaders : undefined;
36
+
35
37
  // Signature: parseInBatches(data, options, url) - Uses registered loaders
36
38
  if (!Array.isArray(loaders) && !isLoaderObject(loaders)) {
37
39
  context = undefined; // context not supported in short signature
@@ -43,11 +45,11 @@ export async function parseInBatches(
43
45
  options = options || {};
44
46
 
45
47
  // Extract a url for auto detection
46
- const {url} = getResourceUrlAndType(data);
48
+ const url = getResourceUrl(data);
47
49
 
48
50
  // Chooses a loader and normalizes it
49
51
  // Note - only uses URL and contentType for streams and iterator inputs
50
- const loader = await selectLoader(data as ArrayBuffer, loaders as Loader[], options);
52
+ const loader = await selectLoader(data as ArrayBuffer, loaders as Loader | Loader[], options);
51
53
  // Note: if options.nothrow was set, it is possible that no loader was found, if so just return null
52
54
  if (!loader) {
53
55
  // @ts-ignore
@@ -55,14 +57,11 @@ export async function parseInBatches(
55
57
  }
56
58
 
57
59
  // Normalize options
58
- // @ts-ignore
59
- options = normalizeOptions(options, loader, loaders, url);
60
- // @ts-ignore
60
+ options = normalizeOptions(options, loader, loaderArray, url);
61
61
  context = getLoaderContext(
62
- // @ts-ignore
63
- {url, parseInBatches, parse, loaders: loaders as Loader[]},
62
+ {url, parseInBatches, parse, loaders: loaderArray},
64
63
  options,
65
- context
64
+ context || null
66
65
  );
67
66
 
68
67
  return await parseWithLoaderInBatches(loader as LoaderWithParser, data, options, context);
@@ -11,7 +11,7 @@ import {isLoaderObject} from '../loader-utils/normalize-loader';
11
11
  import {normalizeOptions} from '../loader-utils/option-utils';
12
12
  import {getArrayBufferOrStringFromDataSync} from '../loader-utils/get-data';
13
13
  import {getLoaderContext, getLoadersFromContext} from '../loader-utils/loader-context';
14
- import {getResourceUrlAndType} from '../utils/resource-utils';
14
+ import {getResourceUrl} from '../utils/resource-utils';
15
15
 
16
16
  /**
17
17
  * Parses `data` synchronously using a specified loader
@@ -52,12 +52,16 @@ export function parseSync(
52
52
  options = normalizeOptions(options, loader, candidateLoaders);
53
53
 
54
54
  // Extract a url for auto detection
55
- const {url} = getResourceUrlAndType(data);
55
+ const url = getResourceUrl(data);
56
56
 
57
57
  const parse = () => {
58
- throw new Error('parseSync called parse');
58
+ throw new Error('parseSync called parse (which is async');
59
59
  };
60
- context = getLoaderContext({url, parseSync, parse, loaders: loaders as Loader[]}, options);
60
+ context = getLoaderContext(
61
+ {url, parseSync, parse, loaders: loaders as Loader[]},
62
+ options,
63
+ context || null
64
+ );
61
65
 
62
66
  return parseWithLoaderSync(loader as LoaderWithParser, data, options, context);
63
67
  }
@@ -9,7 +9,7 @@ import {isResponse} from '../../javascript-utils/is-type';
9
9
  import {normalizeOptions} from '../loader-utils/option-utils';
10
10
  import {getArrayBufferOrStringFromData} from '../loader-utils/get-data';
11
11
  import {getLoaderContext, getLoadersFromContext} from '../loader-utils/loader-context';
12
- import {getResourceUrlAndType} from '../utils/resource-utils';
12
+ import {getResourceUrl} from '../utils/resource-utils';
13
13
  import {selectLoader} from './select-loader';
14
14
 
15
15
  // type LoaderArrayType<T> = T extends (infer Loader)[] ? LoaderOptionsType<Loader> : T
@@ -64,7 +64,7 @@ export async function parse(
64
64
  options = options || ({} as LoaderOptions); // Could be invalid...
65
65
 
66
66
  // Extract a url for auto detection
67
- const {url} = getResourceUrlAndType(data);
67
+ const url = getResourceUrl(data);
68
68
 
69
69
  // Chooses a loader (and normalizes it)
70
70
  // Also use any loaders in the context, new loaders take priority
@@ -81,7 +81,7 @@ export async function parse(
81
81
  options = normalizeOptions(options, loader, candidateLoaders, url); // Could be invalid...
82
82
 
83
83
  // Get a context (if already present, will be unchanged)
84
- context = getLoaderContext({url, parse, loaders: candidateLoaders}, options, context);
84
+ context = getLoaderContext({url, parse, loaders: candidateLoaders}, options, context || null);
85
85
 
86
86
  return await parseWithLoader(loader, data, options, context);
87
87
  }
@@ -2,9 +2,10 @@ import type {LoaderContext, LoaderOptions, Loader} from '@loaders.gl/loader-util
2
2
  import {compareArrayBuffers, path} from '@loaders.gl/loader-utils';
3
3
  import {normalizeLoader} from '../loader-utils/normalize-loader';
4
4
  import {log} from '../utils/log';
5
- import {getResourceUrlAndType} from '../utils/resource-utils';
5
+ import {getResourceUrl, getResourceMIMEType} from '../utils/resource-utils';
6
6
  import {getRegisteredLoaders} from './register-loaders';
7
7
  import {isBlob} from '../../javascript-utils/is-type';
8
+ import {stripQueryString} from '../utils/url-utils';
8
9
 
9
10
  const EXT_PATTERN = /\.([^.]+)$/;
10
11
 
@@ -111,9 +112,10 @@ function selectLoaderInternal(
111
112
  options?: LoaderOptions,
112
113
  context?: LoaderContext
113
114
  ) {
114
- const {url, type} = getResourceUrlAndType(data);
115
+ const url = getResourceUrl(data);
116
+ const type = getResourceMIMEType(data);
115
117
 
116
- const testUrl = url || context?.url;
118
+ const testUrl = stripQueryString(url) || context?.url;
117
119
 
118
120
  let loader: Loader | null = null;
119
121
  let reason: string = '';
@@ -161,7 +163,8 @@ function validHTTPResponse(data: any): boolean {
161
163
 
162
164
  /** Generate a helpful message to help explain why loader selection failed. */
163
165
  function getNoValidLoaderMessage(data): string {
164
- const {url, type} = getResourceUrlAndType(data);
166
+ const url = getResourceUrl(data);
167
+ const type = getResourceMIMEType(data);
165
168
 
166
169
  let message = 'No valid loader found (';
167
170
  message += url ? `${path.filename(url)}, ` : 'no url provided, ';
@@ -1,5 +1,7 @@
1
1
  import type {Loader, LoaderOptions, LoaderContext} from '@loaders.gl/loader-utils';
2
2
  import {getFetchFunction} from './get-fetch-function';
3
+ import {extractQueryString, stripQueryString} from '../utils/url-utils';
4
+ import {path} from '@loaders.gl/loader-utils';
3
5
 
4
6
  /**
5
7
  * "sub" loaders invoked by other loaders get a "context" injected on `this`
@@ -12,26 +14,35 @@ import {getFetchFunction} from './get-fetch-function';
12
14
  */
13
15
  export function getLoaderContext(
14
16
  context: Omit<LoaderContext, 'fetch'> & Partial<Pick<LoaderContext, 'fetch'>>,
15
- options?: LoaderOptions,
16
- previousContext: LoaderContext | null = null
17
+ options: LoaderOptions,
18
+ parentContext: LoaderContext | null
17
19
  ): LoaderContext {
18
20
  // For recursive calls, we already have a context
19
21
  // TODO - add any additional loaders to context?
20
- if (previousContext) {
21
- return previousContext;
22
+ if (parentContext) {
23
+ return parentContext;
22
24
  }
23
25
 
24
- const resolvedContext: LoaderContext = {
26
+ const newContext: LoaderContext = {
25
27
  fetch: getFetchFunction(options, context),
26
28
  ...context
27
29
  };
28
30
 
31
+ // Parse URLs so that subloaders can easily generate correct strings
32
+ if (newContext.url) {
33
+ const baseUrl = stripQueryString(newContext.url);
34
+ newContext.baseUrl = baseUrl;
35
+ newContext.queryString = extractQueryString(newContext.url);
36
+ newContext.filename = path.filename(baseUrl);
37
+ newContext.baseUrl = path.dirname(baseUrl);
38
+ }
39
+
29
40
  // Recursive loading does not use single loader
30
- if (!Array.isArray(resolvedContext.loaders)) {
31
- resolvedContext.loaders = null;
41
+ if (!Array.isArray(newContext.loaders)) {
42
+ newContext.loaders = null;
32
43
  }
33
44
 
34
- return resolvedContext;
45
+ return newContext;
35
46
  }
36
47
 
37
48
  // eslint-disable-next-line complexity
@@ -1,51 +1,73 @@
1
+ // loaders.gl, MIT license
2
+
1
3
  import {isResponse, isBlob} from '../../javascript-utils/is-type';
2
4
  import {parseMIMEType, parseMIMETypeFromURL} from './mime-type-utils';
5
+ import {stripQueryString} from './url-utils';
3
6
 
4
- const QUERY_STRING_PATTERN = /\?.*/;
7
+ /**
8
+ * A loadable resource. Includes:
9
+ * `Response`, `Blob` (`File` is a subclass), string URLs and data URLs
10
+ */
11
+ export type Resource = Response | Blob | string;
5
12
 
6
13
  /**
7
- * Returns an object with `url` and (MIME) `type` fields
8
- * If it cannot determine url or type, the corresponding value will be an empty string
14
+ * Returns the URL associated with this resource.
15
+ * The returned value may include a query string and need further processing.
16
+ * If it cannot determine url, the corresponding value will be an empty string
9
17
  *
10
- * @param resource Any type, but only Responses, string URLs and data URLs are processed
18
+ * @todo string parameters are assumed to be URLs
19
+ */
20
+ export function getResourceUrl(resource: unknown): string {
21
+ // If resource is a `Response`, it contains the information directly as a field
22
+ if (isResponse(resource)) {
23
+ const response = resource as Response;
24
+ return response.url;
25
+ }
26
+
27
+ // If the resource is a Blob or a File (subclass of Blob)
28
+ if (isBlob(resource)) {
29
+ const blob = resource as Blob;
30
+ // File objects have a "name" property. Blob objects don't have any
31
+ // url (name) information
32
+ return blob.name || '';
33
+ }
34
+
35
+ if (typeof resource === 'string') {
36
+ return resource;
37
+ }
38
+
39
+ // Unknown
40
+ return '';
41
+ }
42
+
43
+ /**
44
+ * Returns the URL associated with this resource.
45
+ * The returned value may include a query string and need further processing.
46
+ * If it cannot determine url, the corresponding value will be an empty string
11
47
  *
12
48
  * @todo string parameters are assumed to be URLs
13
49
  */
14
- export function getResourceUrlAndType(resource: any): {url: string; type: string} {
50
+ export function getResourceMIMEType(resource: unknown): string {
15
51
  // If resource is a response, it contains the information directly
16
52
  if (isResponse(resource)) {
17
- const url = stripQueryString(resource.url || '');
18
- const contentTypeHeader = resource.headers.get('content-type') || '';
19
- return {
20
- url,
21
- type: parseMIMEType(contentTypeHeader) || parseMIMETypeFromURL(url)
22
- };
53
+ const response = resource as Response;
54
+ const contentTypeHeader = response.headers.get('content-type') || '';
55
+ const noQueryUrl = stripQueryString(response.url);
56
+ return parseMIMEType(contentTypeHeader) || parseMIMETypeFromURL(noQueryUrl);
23
57
  }
24
58
 
25
59
  // If the resource is a Blob or a File (subclass of Blob)
26
60
  if (isBlob(resource)) {
27
- return {
28
- // File objects have a "name" property. Blob objects don't have any
29
- // url (name) information
30
- url: stripQueryString(resource.name || ''),
31
- type: resource.type || ''
32
- };
61
+ const blob = resource as Blob;
62
+ return blob.type || '';
33
63
  }
34
64
 
35
65
  if (typeof resource === 'string') {
36
- return {
37
- // TODO this could mess up data URL but it doesn't matter as it is just used for inference
38
- url: stripQueryString(resource),
39
- // If a data url
40
- type: parseMIMETypeFromURL(resource)
41
- };
66
+ return parseMIMETypeFromURL(resource);
42
67
  }
43
68
 
44
69
  // Unknown
45
- return {
46
- url: '',
47
- type: ''
48
- };
70
+ return '';
49
71
  }
50
72
 
51
73
  /**
@@ -55,12 +77,14 @@ export function getResourceUrlAndType(resource: any): {url: string; type: string
55
77
 
56
78
  * @note string parameters are NOT assumed to be URLs
57
79
  */
58
- export function getResourceContentLength(resource: any): number {
80
+ export function getResourceContentLength(resource: unknown): number {
59
81
  if (isResponse(resource)) {
60
- return resource.headers['content-length'] || -1;
82
+ const response = resource as Response;
83
+ return response.headers['content-length'] || -1;
61
84
  }
62
85
  if (isBlob(resource)) {
63
- return resource.size;
86
+ const blob = resource as Blob;
87
+ return blob.size;
64
88
  }
65
89
  if (typeof resource === 'string') {
66
90
  // TODO - handle data URL?
@@ -74,7 +98,3 @@ export function getResourceContentLength(resource: any): number {
74
98
  }
75
99
  return -1;
76
100
  }
77
-
78
- function stripQueryString(url) {
79
- return url.replace(QUERY_STRING_PATTERN, '');
80
- }
@@ -1,5 +1,5 @@
1
1
  import {isResponse} from '../../javascript-utils/is-type';
2
- import {getResourceContentLength, getResourceUrlAndType} from './resource-utils';
2
+ import {getResourceContentLength, getResourceUrl, getResourceMIMEType} from './resource-utils';
3
3
 
4
4
  /**
5
5
  * Returns a Response object
@@ -22,7 +22,8 @@ export async function makeResponse(resource: any): Promise<Response> {
22
22
 
23
23
  // `new Response(File)` does not preserve content-type and URL
24
24
  // so we add them here
25
- const {url, type} = getResourceUrlAndType(resource);
25
+ const url = getResourceUrl(resource);
26
+ const type = getResourceMIMEType(resource);
26
27
  if (type) {
27
28
  headers['content-type'] = type;
28
29
  }
@@ -0,0 +1,12 @@
1
+ // loaders.gl, MIT license
2
+
3
+ const QUERY_STRING_PATTERN = /\?.*/;
4
+
5
+ export function extractQueryString(url): string {
6
+ const matches = url.match(QUERY_STRING_PATTERN);
7
+ return matches && matches[0];
8
+ }
9
+
10
+ export function stripQueryString(url): string {
11
+ return url.replace(QUERY_STRING_PATTERN, '');
12
+ }