# API reference ## Module forms The CommonJS root is the webpack loader function: ```js const resolveUrlLoader = require('@stackline/resolve-url-loader') ``` It is callable and has exactly these five enumerable helper properties, in order: `asGenerator`, `createJoinImplementation`, `createJoinFunction`, `defaultJoinGenerator`, `defaultJoin`. The root therefore exposes six callable public values total: the loader itself and five attached helpers. Both the immutable `resolve-url-loader@5.0.0` baseline and this package have that shape. ESM consumers can use the default import and the same five named helpers: ```js import loader, { asGenerator, createJoinImplementation, createJoinFunction, defaultJoinGenerator, defaultJoin } from '@stackline/resolve-url-loader' ``` `index.mjs` is an additive default-and-named facade. The CommonJS root keeps statically discoverable property assignments for Node's ESM bridge. No restrictive `exports` map is present, preserving historical deep resolution. ## `resolveUrlLoader(content, sourceMap)` The default export is a webpack loader, not an ordinary standalone function. Webpack binds a loader context as `this`; the function reads options and filesystem state from that context and completes asynchronous processing through `this.async()`. ```js module.exports = { devtool: 'source-map', module: { rules: [{ test: /\.scss$/, use: [ 'css-loader', { loader: '@stackline/resolve-url-loader', options: { sourceMap: true } }, { loader: 'sass-loader', options: { sourceMap: true } } ] }] } } ``` Webpack evaluates this array from right to left: Sass runs first, this loader runs immediately afterward, and `css-loader` consumes the rewritten result. Source maps must remain enabled in the upstream Sass loader regardless of the top-level webpack `devtool` setting. ### Parameters and completion | Value | Contract | | --- | --- | | `content` | CSS string emitted by the preceding loader. | | `sourceMap` | Source-map object, JSON-encoded source-map string, `null`, or `undefined`. | | `this` | Webpack loader context with `resourcePath`, `context`, `fs`, option access, diagnostics, caching, and async callback methods. | | callback content | Rewritten CSS. | | callback map | Adjusted source map when `sourceMap` output is enabled; omitted otherwise. | The loader marks its result cacheable. On webpack 4 it emits source-relative map sources; on webpack 5 it emits project-relative map sources. A malformed JSON map, codec failure, invalid option, absent usable map at a URL declaration, or CSS-processing failure follows the established warning/error categories and webpack callback behavior. ### Options | Option | Type | Default | Behavior | | --- | --- | --- | --- | | `sourceMap` | `boolean` | `loader.sourceMap` | Include an outgoing source map. This does not create missing upstream source information. | | `silent` | `boolean` | `false` | Suppress warnings and option deprecation messages. Errors still report. | | `removeCR` | `boolean` | `true` when the host EOL contains CR, otherwise `false` | Replace orphan carriage returns before PostCSS position lookup. | | `root` | `false \| string` | `false` | Permit root-relative URL processing. A non-empty string must be an absolute existing directory; an empty string retains the upstream special case. | | `debug` | `boolean \| (message) => void` | `false` | Log deduplicated join attempts to `console.log` or the supplied function. | | `join` | join function | `defaultJoin` | Produce the one-item URL resolver used by the CSS value processor. | The removed upstream-era options `engine`, `keepQuery`, `absolute`, `attempts`, `includeRoot`, and `fail` trigger their established deprecation messages when present. They do not regain their former behavior. ### URL behavior The value processor handles multiple quoted or unquoted `url()` statements in one declaration. It preserves query strings and fragments. Fully relative file URLs are candidates for resolution. Absolute paths are candidates only when `root` is a string. HTTP(S), data, module-relative `~`, empty, and other non-file URL forms pass through unchanged. The resulting absolute filesystem path is made relative to the CSS resource directory, path separators become forward slashes, and `loader-utils` converts the result to a webpack request form. ## Join data types A join generator and implementation exchange these logical values: ```ts interface JoinItem { uri: string query: string isAbsolute: boolean bases: { subString: string value: string property: string selector: string } } interface JoinAttempt { base: string uri: string joined: string isSuccess: boolean isFallback: boolean } ``` The four bases come from reverse source-map lookups at increasingly broad positions in the original declaration. The default relative strategy tries `subString`, `value`, `property`, then `selector`, removing duplicates while preserving order. ## `asGenerator(generator)` Normalizes a custom generator so it always returns an iterator of two-item `[base, uri]` tuples. ```js const generator = asGenerator((item) => [ item.bases.subString, [item.bases.selector, item.uri] ]) ``` An array result may contain a base string or a partial tuple. Missing tuple positions are filled with `null` and the item's original URI. Duplicate tuples are removed. An iterator result is accepted when it has a zero-argument `next()` method. Anything else throws `TypeError`. ## `createJoinImplementation(generator)` Creates the high-level attempt producer used by a join function: ```js const implementation = createJoinImplementation(generator) const attempts = implementation(item, options, loaderContext) ``` The generator is invoked lazily. The implementation: - requires a real iterator; - evaluates at most 100,000 steps; - accepts only two-item tuples; - ignores falsey non-string tuple positions, but rejects truthy invalid types; - validates a relative candidate base as an absolute existing directory using `loader.fs.statSync()`; - permits `base === options.root` for an absolute item, retaining the empty-root special case; - normalizes `path.join(base, uri)`; - records every valid filesystem attempt; and - stops after the first existing file. Every recorded default attempt has `isFallback: true`. An existing regular file has `isSuccess: true`; directories are not successful URL targets. ## `createJoinFunction(name, implementation)` Wraps a low-level attempt implementation as a loader option: ```js const customJoin = createJoinFunction('customJoin', (item, options, loader) => [ { base: item.bases.value, uri: item.uri, joined: '/absolute/project/asset.png', isSuccess: true, isFallback: false } ]) ``` Calling `customJoin(options, loader)` returns the required one-argument `join(item)` function. For each item, it verifies that every attempt contains string `base`, `uri`, and `joined` fields plus boolean `isSuccess` and `isFallback` fields. It logs the attempt table when debugging is active, then returns: 1. the first successful joined path; 2. otherwise the first fallback joined path; or 3. otherwise `null`, leaving the CSS URL unchanged. A non-null result must be an absolute path. A named join has stable diagnostic `toString()` and `toJSON()` values of `[Function name]`. ## `defaultJoinGenerator` The normalized built-in generator. For a relative URL it yields the four source-map bases in order: substring, value, property, selector. For an absolute URL it yields only `options.root`. ## `defaultJoin` The built-in two-argument join function, created by composing `defaultJoinGenerator`, `createJoinImplementation()`, and `createJoinFunction('defaultJoin', ...)`. ```js const joinOne = defaultJoin(options, loaderContext) const absoluteOrNull = joinOne(item) ``` ## Historical deep imports The eight upstream JavaScript entries remain packed and addressable because the package does not impose an `exports` allowlist: | Entry | Export | | --- | --- | | `lib/engine/postcss` | Async PostCSS CSS/source-map processor. | | `lib/file-protocol` | `prepend()` and `remove()` source/file protocol helpers. | | `lib/join-function` | The five join helpers attached to the root. | | `lib/join-function/debug` | `pathToString()`, `formatJoinMessage()`, and `createDebugLogger()`. | | `lib/join-function/fs-utils` | Factory for synchronous file/directory predicates over webpack's filesystem. | | `lib/log-to-test-harness` | Historical one-shot option logger used by the upstream harness contract. | | `lib/position-algerbra` | `sanitise()`, `strToOffset()`, and `add()`; the historical misspelling is preserved. | | `lib/value-processor` | Factory for the CSS declaration URL transformer. | Imports may include or omit `.js`. First-party declarations are added beside these entries. Their established behavior is preserved, but direct mutation of private internals remains unsupported. The files beneath `lib/vendor/adjust-sourcemap-loader/` are vendored implementation and provenance material. Their presence is not a new public API commitment. ## Windows file-URL correction `lib/file-protocol.remove()` retains ordinary `file://` removal and adds one bounded, platform-specific correction: ```text Windows: file:///D:/project/src/card.scss -> D:/project/src/card.scss POSIX: file:///D:/literal-posix-name -> /D:/literal-posix-name POSIX: file:///srv/project/card.scss -> /srv/project/card.scss ``` On Windows only, the extra leading slash is removed when the post-protocol value begins with `/`, an ASCII drive letter, `:`, and a slash or backslash. This addresses the Windows absolute-directory failure without reinterpreting a valid drive-looking POSIX filename or changing any other POSIX-rooted source. ## TypeScript The root declarations support CommonJS `export =` and declare the loader context, source map, options, join item, attempt, iterator, implementation, and factory types. The additive `.d.mts` facade exposes the default loader and the five named helpers. TypeScript 3.9 and the current compiler are tested. ```ts import loader = require('@stackline/resolve-url-loader') const options: loader.Options = { sourceMap: true, debug: (message) => console.log(message), join: loader.defaultJoin } ``` ## Runtime boundary Node.js 12 or newer is supported. The package is designed only for execution inside webpack's Node loader pipeline. It has no browser runtime or browser build, and it is not a standalone PostCSS plugin, Vite plugin, URL sanitizer, filesystem containment mechanism, or network fetcher. See [COMPATIBILITY_CONTRACT.md](./COMPATIBILITY_CONTRACT.md) for the exact preservation boundary, [MIGRATION.md](./MIGRATION.md) for adoption choices, and [SECURITY.md](./SECURITY.md) for reporting and safe-use guidance.