-
-
Notifications
You must be signed in to change notification settings - Fork 1.4k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c46b401
commit 70262c6
Showing
9 changed files
with
442 additions
and
12 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,63 @@ | ||
/** | ||
* Transform d3 ESM libraries to vendored CommonJS libraries | ||
* | ||
* This produces `lib-vendor/d3-<package name>/src` files that have | ||
* internally consistent references to other d3 packages. It is only meant | ||
* to be used for the CommonJS import path. | ||
*/ | ||
const path = require("path"); | ||
|
||
module.exports = { | ||
only: ["node_modules/*/src/**/*.js"], | ||
plugins: [ | ||
[ | ||
"@babel/transform-modules-commonjs", | ||
{ | ||
strict: false, | ||
allowTopLevelThis: true, | ||
}, | ||
], | ||
[ | ||
"module-resolver", | ||
{ | ||
// Convert all imports for _other_ d3 dependencies to the relative | ||
// path in our vendor package. | ||
resolvePath(sourcePath, currentFile) { | ||
const d3pattern = /^(?<pkg>(d3-[^\/]+|internmap))(?<path>.*)/; | ||
const match = d3pattern.exec(sourcePath); | ||
if (match) { | ||
// We're assuming a common shape of d3 packages: | ||
// - Only top level imports "d3-<whatever>" | ||
// - With no path components (like "d3-<whatever>/path/to.js") | ||
if (match.groups.path) { | ||
throw new Error( | ||
`Unable to process ${sourcePath} import in ${currentFile}`, | ||
); | ||
} | ||
|
||
// Get Vendor package path. | ||
const vendorPkg = `lib-vendor/${match.groups.pkg}/src/index.js`; | ||
|
||
// Derive relative path to vendor lib to have a file like move from: | ||
// - 'node_modules/d3-interpolate/src/rgb.js' | ||
// - 'lib-vendor/d3-interpolate/src/rgb.js' | ||
// and have an import transform like: | ||
// - `d3-color` | ||
// - `../../d3-color` | ||
const currentFileVendor = currentFile.replace( | ||
/^node_modules/, | ||
"lib-vendor", | ||
); | ||
const relPathToPkg = path | ||
.relative(path.dirname(currentFileVendor), vendorPkg) | ||
.replace(/\\/g, "/"); | ||
|
||
return relPathToPkg; | ||
} | ||
|
||
return sourcePath; | ||
}, | ||
}, | ||
], | ||
], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
/lib-vendor | ||
/d3-* | ||
/internmap.js |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,70 @@ | ||
# VictoryVendor | ||
|
||
Vendored dependencies for Victory. | ||
|
||
## Background | ||
|
||
D3 has released most of its libraries as ESM-only. This means that consumers in Node.js applications can no longer just `require()` anything with a d3 transitive dependency, including much of Victory. | ||
|
||
To help provide an easy path to folks still using CommonJS in their Node.js applications that consume Victory, we now provide this package to vendor in various d3-related packages. | ||
|
||
## Packages | ||
|
||
We presently provide the following top-level libraries: | ||
<!-- cat packages/victory-vendor/package.json | egrep '"d3-' | egrep -o 'd3-[^"]*'| sor t--> | ||
|
||
- d3-ease | ||
- d3-interpolate | ||
- d3-scale | ||
- d3-shape | ||
- d3-timer | ||
|
||
This is the total list of top and transitive libraries we vendor: | ||
<!-- ls packages/victory-vendor/lib-vendor | sort --> | ||
|
||
- d3-array | ||
- d3-color | ||
- d3-ease | ||
- d3-format | ||
- d3-interpolate | ||
- d3-path | ||
- d3-scale | ||
- d3-shape | ||
- d3-time | ||
- d3-time-format | ||
- d3-timer | ||
- internmap | ||
|
||
Note that this does _not_ include the following D3 libraries that still support CommonJS: | ||
|
||
- d3-voronoi | ||
|
||
## How it works | ||
|
||
We provide two alternate paths and behaviors -- for ESM and CommonJS | ||
|
||
### ESM | ||
|
||
If you do a Node.js import like: | ||
|
||
```js | ||
import { interpolate } from "victory-vendor/d3-interpolate"; | ||
``` | ||
|
||
under the hood it's going to just re-export and pass you through to `node_modules/d3-interpolate`, the **real** ESM library from D3. | ||
|
||
### CommonJS | ||
|
||
If you do a Node.js import like: | ||
|
||
```js | ||
const { interpolate } = require("victory-vendor/d3-interpolate"); | ||
``` | ||
|
||
under the hood it's going to will go to an alternate path that contains the transpiled version of the underlying d3 library to be found at `victory-vendor/lib-vendor/d3-interpolate/**/*.js`. This futher has internally consistent import references to other `victory-vendor/lib-vendor/<pkg-name>` paths. | ||
|
||
Note that for some tooling (like Jest) that doesn't play well with `package.json:exports` routing to this CommonJS path, we **also** output a root file in the form of `victory-vendor/d3-interpolate.js`. | ||
|
||
## Licenses | ||
|
||
This project is released under the MIT license, but the vendor'ed in libraries include other licenses (e.g. ISC) that we enumerate in our `package.json:license` field. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,53 @@ | ||
{ | ||
"name": "mui/x-charts-vendor", | ||
"version": "37.0.2", | ||
"description": "Vendored dependencies for Victory", | ||
"keywords": [ | ||
"data visualization", | ||
"React", | ||
"d3", | ||
"charting" | ||
], | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/mui/mui-x" | ||
}, | ||
"author": "Formidable", | ||
"license": "MIT AND ISC", | ||
"exports": { | ||
"./package.json": "./package.json", | ||
"./d3-*": { | ||
"types": "./d3-*.d.ts", | ||
"import": "./es/d3-*.js", | ||
"default": "./lib/d3-*.js" | ||
} | ||
}, | ||
"dependencies": { | ||
"d3-color": "^3.1.0", | ||
"d3-delaunay": "^6.0.4", | ||
"d3-interpolate": "^3.0.1", | ||
"d3-scale": "^4.0.2", | ||
"d3-shape": "^3.2.0", | ||
"@types/d3-color": "^3.1.3", | ||
"@types/d3-delaunay": "^6.0.4", | ||
"@types/d3-interpolate": "^3.0.4", | ||
"@types/d3-scale": "^4.0.8", | ||
"@types/d3-shape": "^3.1.6" | ||
}, | ||
"devDependencies": { | ||
"d3-color": "^3.1.0", | ||
"d3-format": "^3.1.0", | ||
"d3-path": "^3.0.1", | ||
"d3-time-format": "^4.1.0", | ||
"d3-voronoi": "^1.1.4", | ||
"internmap": "^2.0.3", | ||
"execa": "^6.1.0", | ||
"rimraf": "^3.0.2" | ||
}, | ||
"publishConfig": { | ||
"provenance": true | ||
}, | ||
"scripts": { | ||
"build": "node ./scripts/build.js" | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,169 @@ | ||
/* global __dirname:false */ | ||
/** | ||
* Build d3 vendor libraries from `node_modules`. | ||
* | ||
* **Note - transitive dependencies**: Because pnpm lacks a `nohoist` option, | ||
* if you have a `d3-*` dependency that has a transitive dependency on another | ||
* module (e.g., `d3-interpolate` depends on `d3-color`) you need to add a | ||
* compatible version to `package.json:devDependencies` here to make sure we | ||
* get the library in our `node_modules` and appropriately build it. | ||
*/ | ||
const fs = require("fs").promises; | ||
const path = require("path"); | ||
const { promisify } = require("util"); | ||
|
||
const rimraf = require("rimraf"); | ||
const rimrafP = promisify(rimraf); | ||
|
||
const vendorPkg = require("../package.json"); | ||
const VENDOR_PKGS = new Set(Object.keys(vendorPkg.dependencies)); | ||
|
||
const { log, error } = console; // eslint-disable-line no-undef | ||
|
||
// Templates. | ||
const getEsmIndex = (pkg) => ` | ||
// \`x-charts-vendor/${pkg.name}\` (ESM) | ||
// See upstream license: ${pkg.repository.url.replace( | ||
/\.git$/, | ||
"", | ||
)}/blob/main/LICENSE | ||
// | ||
// Our ESM package uses the underlying installed dependencies of \`node_modules/${ | ||
pkg.name | ||
}\` | ||
export * from "${pkg.name}"; | ||
`; | ||
|
||
const getCjsIndex = (pkg) => ` | ||
// \`x-charts-vendor/${pkg.name}\` (CommonJS) | ||
// See upstream license: ${pkg.repository.url.replace( | ||
/\.git$/, | ||
"", | ||
)}/blob/main/LICENSE | ||
// | ||
// Our CommonJS package relies on transpiled vendor files in \`lib-vendor/${ | ||
pkg.name | ||
}\` | ||
module.exports = require("../lib-vendor/${pkg.name}/src/index.js"); | ||
`; | ||
|
||
const getCjsRootIndex = (pkg) => ` | ||
// \`x-charts-vendor/${pkg.name}\` (CommonJS) | ||
// See upstream license: ${pkg.repository.url.replace( | ||
/\.git$/, | ||
"", | ||
)}/blob/main/LICENSE | ||
// | ||
// This file only exists for tooling that doesn't work yet with package.json:exports | ||
// by proxying through the CommonJS version. | ||
module.exports = require("./lib/${pkg.name}"); | ||
`; | ||
|
||
const getTypeDefinitionFile = (pkg) => ` | ||
// \`x-charts-vendor/${pkg.name}\` (TypeScript) | ||
// | ||
// Export the type definitions for this package: | ||
export * from "${pkg.name}"; | ||
`; | ||
|
||
// Main. | ||
const main = async () => { | ||
// Lazy ESM imports. | ||
const { execa } = await import("execa"); | ||
|
||
// Get d3-related packages we want to vendor. | ||
const pkgs = ( | ||
await fs.readdir(path.resolve(__dirname, "../node_modules/")) | ||
).filter((name) => /^(d3-|internmap)/.test(name)); | ||
|
||
// Safety check: we assume that **all** are flattened to root level of this | ||
// package, and want to make sure there are no nested dependencies. | ||
for (const pkgName of pkgs) { | ||
const pkgModsPath = path.resolve( | ||
__dirname, | ||
`../node_modules/git${pkgName}/node_modules`, | ||
); | ||
const stat = await fs.lstat(pkgModsPath).catch(() => null); | ||
if (stat) { | ||
throw new Error(`Found nested modules: ${pkgModsPath}`); | ||
} | ||
} | ||
|
||
// Clean out and ensure base library paths exist | ||
const EsmBasePath = path.resolve(__dirname, `../es`); | ||
const CjsBasePath = path.resolve(__dirname, `../lib`); | ||
const VendorBasePath = path.resolve(__dirname, `../lib-vendor`); | ||
const baseDirs = [EsmBasePath, CjsBasePath, VendorBasePath]; | ||
const cleanGlobs = [].concat(baseDirs, path.resolve(__dirname, "../d3-*")); | ||
|
||
log("Cleaning old vendor directories."); | ||
await Promise.all(cleanGlobs.map((glob) => rimrafP(glob))); | ||
log("Creating empty vendor directories."); | ||
await Promise.all( | ||
baseDirs.map((libPath) => fs.mkdir(libPath, { recursive: true })), | ||
); | ||
|
||
// Transpile. | ||
log("Transpiling vendor sources."); | ||
await execa( | ||
"pnpm", | ||
[ | ||
"babel", | ||
"--config-file", | ||
path.resolve(__dirname, "../.babelrc.js"), | ||
"-d", | ||
path.resolve(__dirname, "../lib-vendor"), | ||
path.resolve(__dirname, "../node_modules"), | ||
], | ||
{ | ||
stdio: "inherit", | ||
}, | ||
); | ||
|
||
// Iterate and generate index files. | ||
log("Copying licenses and generating indexes."); | ||
for (const pkgName of pkgs) { | ||
log(`- ${pkgName}`); | ||
|
||
const pkgBase = path.resolve(__dirname, `../node_modules/${pkgName}`); | ||
const pkgPath = path.join(pkgBase, `package.json`); | ||
const pkg = await fs | ||
.readFile(pkgPath) | ||
.then((buf) => JSON.parse(buf.toString())); | ||
const libVendorPath = path.resolve(__dirname, `../lib-vendor/${pkgName}`); | ||
|
||
// Create library indexes and copy licenses to `lib-vendor. | ||
await Promise.all([ | ||
fs.writeFile(path.join(EsmBasePath, `${pkgName}.js`), getEsmIndex(pkg)), | ||
fs.writeFile(path.join(CjsBasePath, `${pkgName}.js`), getCjsIndex(pkg)), | ||
fs.copyFile( | ||
path.join(pkgBase, "LICENSE"), | ||
path.join(libVendorPath, "LICENSE"), | ||
), | ||
// Root hack file for non package.json:exports systems | ||
VENDOR_PKGS.has(pkgName) && | ||
fs.writeFile( | ||
path.resolve(__dirname, `../${pkgName}.js`), | ||
getCjsRootIndex(pkg), | ||
), | ||
// Generate TypeScript definitions | ||
VENDOR_PKGS.has(pkgName) && | ||
fs.writeFile( | ||
path.resolve(__dirname, `../${pkgName}.d.ts`), | ||
getTypeDefinitionFile(pkg), | ||
), | ||
]); | ||
} | ||
}; | ||
|
||
if (require.main === module) { | ||
main() | ||
// eslint-disable-next-line promise/always-return | ||
.then(() => { | ||
log("Build finished."); | ||
}) | ||
.catch((err) => { | ||
error(err); | ||
process.exit(-1); | ||
}); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
/* | ||
* This test verifies that these modules and types are exported correctly | ||
*/ | ||
|
||
/* eslint-disable @typescript-eslint/no-unused-vars */ | ||
import { | ||
// @ts-expect-error Make sure invalid imports fail: | ||
INVALID_TYPE, | ||
interpolate, | ||
NumberArray, | ||
} from "@mui/x-charts/d3-interpolate"; | ||
|
||
describe("d3-interpolate", () => { | ||
it("exports valid functions", () => { | ||
expect(interpolate).toBeInstanceOf(Function); | ||
}); | ||
}); |
Oops, something went wrong.