ソースを参照

Put projection transformations to d3

Let d3 handle the centering of the projections to the specified bounds.

Also start working on consuming bbox data.
master
コミット
567ae8be0a
12個のファイルの変更148799行の追加210行の削除
  1. バイナリ
      __fixtures__/biomes-test.png
  2. +3
    -1
      package.json
  3. +52
    -0
      scripts/generate-bounding-box-data/index.ts
  4. +260
    -0
      scripts/generate-bounding-box-data/ne_10m_admin_0_countries.json
  5. +148051
    -0
      scripts/generate-bounding-box-data/sample-russia.json
  6. +3
    -0
      src/geo.ts
  7. +2
    -207
      src/index.ts
  8. +15
    -0
      src/png.ts
  9. +302
    -0
      src/projection.ts
  10. +2
    -1
      tsconfig.json
  11. +22
    -0
      tsconfig.script.json
  12. +87
    -1
      yarn.lock

バイナリ
__fixtures__/biomes-test.png ファイルの表示

変更前 変更後
幅: 461  |  高さ: 231  |  サイズ: 32 KiB

+ 3
- 1
package.json ファイルの表示

@@ -59,6 +59,7 @@
"eslint-config-lxsmnsyc": "^0.4.0",
"fast-check": "^2.24.0",
"pridepack": "1.1.0",
"ts-node": "^10.7.0",
"tslib": "^2.3.1",
"typescript": "^4.5.4",
"vitest": "^0.2.5"
@@ -72,7 +73,8 @@
"watch": "pridepack watch",
"start": "pridepack start",
"dev": "pridepack dev",
"test": "vitest"
"test": "vitest",
"generate-bounding-box-data": "ts-node --project tsconfig.script.json scripts/generate-bounding-box-data/index.ts"
},
"private": false,
"description": "Utility for map projections.",


+ 52
- 0
scripts/generate-bounding-box-data/index.ts ファイルの表示

@@ -0,0 +1,52 @@
import { readFile, writeFile } from 'fs/promises';

// const getBoundingBox = (coordinates: any) => {
// return coordinates.reduce(
// (coordinatesBoundingBox, polygonGroup) => {
// const pg = polygonGroup.reduce(
// (polygonGroupBoundingBox, polygon) => {
// return [
// Math.min()
// ]
// },
// coordinatesBoundingBox
// )
// },
// [[180, -90], [-180, 90]]
// )
// }

const main = async () => {
let json;
try {
const jsonBuffer = await readFile('scripts/generate-bounding-box-data/ne_10m_admin_0_countries.json');
const jsonString = jsonBuffer.toString('utf-8');
json = JSON.parse(jsonString);
} catch {
process.stderr.write('Unable to read Admin 0 Countries GeoJSON. Obtain data from Natural Earth and convert to GeoJSON.');
process.exit(1);
return;
}

const recognizedCountries = json.features.filter(f => f.properties['ISO_A2_EH'] !== '-99');
await writeFile(
'scripts/generate-bounding-box-data/sample-russia.json',
JSON.stringify(
json.features.find(f => f.properties['NAME'] === 'Russia'),
null,
2
)
);

const countries = recognizedCountries.map(f => ({
name: f.properties['NAME'],
countryCode: f.properties['ISO_A2_EH'],
}))
.sort((a, b) => a.name.localeCompare(b.name));

countries.forEach(c => {
console.log(c);
})
}

void main();

+ 260
- 0
scripts/generate-bounding-box-data/ne_10m_admin_0_countries.json
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 148051
- 0
scripts/generate-bounding-box-data/sample-russia.json
ファイル差分が大きすぎるため省略します
ファイルの表示


+ 3
- 0
src/geo.ts ファイルの表示

@@ -0,0 +1,3 @@
export const getBounds = () => {

}

+ 2
- 207
src/index.ts ファイルの表示

@@ -1,207 +1,2 @@
import * as d3geo from 'd3-geo';
import * as d3geoProjection from 'd3-geo-projection';
import * as d3geoPolygon from 'd3-geo-polygon';
import { PNG } from 'pngjs';
import { readFile } from 'fs/promises';

type Coords = [number, number]
type Bounds = [Coords, Coords]

type ProjectionFunction = (...args: unknown[]) => d3geo.GeoProjection;

const referenceWidth = 960 as const;
const referenceHeight = 480 as const;

type ProjectOptions = {
inputDimensions?: { width: number, height: number },
bounds?: Bounds,
wrapAround?: boolean,
}

type Projection = [string, ...unknown[]]

const getCenter = (bounds: Bounds): Coords => {
const [nw, se] = bounds;
const [nwLng, nwLat] = nw;
const [seLng, seLat] = se;
return [
// TODO: better center checking that wraps longitudes
(nwLng + seLng) / 2,
(nwLat + seLat) / 2,
];
};

const getProjectionFunctionSource = (projectionFunctionName: string): Record<string, unknown> => {
if (projectionFunctionName in d3geoPolygon) {
return d3geoPolygon as Record<string, unknown>;
}
if (projectionFunctionName in d3geoProjection) {
return d3geoProjection as Record<string, unknown>;
}
if (projectionFunctionName in d3geo) {
return d3geo as Record<string, unknown>;
}

throw new Error(`Unknown projection: ${projectionFunctionName}`);
};

const buildProjectionFunction = (projection: Projection, options: ProjectOptions = {}) => {
const [projectionName, ...projectionArgs] = projection;
const projectionFunctionName = `geo${projectionName}`;
const geoProjectionSource = getProjectionFunctionSource(projectionFunctionName);
const projectionFn = geoProjectionSource[projectionFunctionName] as ProjectionFunction;
const baseProjection = projectionFn(...projectionArgs) as unknown as d3geo.GeoProjection;
const {
bounds = [[-180, 90], [180, -90]],
} = options;

return baseProjection.center(getCenter(bounds));
};

export const projectPoint = (
point: [number, number],
projection: Projection,
options: ProjectOptions = {},
): [number, number] | null => {
const [x, y] = point;

const [projectionName] = projection;
if (projectionName === 'Equirectangular') {
return point;
}

const {
inputDimensions = { width: referenceWidth, height: referenceHeight },
wrapAround = false,
} = options;

const projectionFunction = buildProjectionFunction(projection, options);
if (!projectionFunction.invert) {
return null;
}

const { width: sx, height: sy } = inputDimensions;
const originalPoint = [
(x / sx) * referenceWidth,
(y / sy) * referenceHeight,
] as [number, number];
const inverted = projectionFunction.invert(originalPoint);

if (!inverted) {
return null;
}

if (wrapAround) {
return inverted;
}

const validation = projectionFunction(inverted);
if (!validation) {
return null;
}

// https://stackoverflow.com/questions/41832043/how-to-fix-map-boundaries-on-d3-cartographic-raster-reprojection/41856996#41856996
const tolerance = 0.5;

if (
Math.abs(validation[0] - originalPoint[0]) < tolerance
&& Math.abs(validation[1] - originalPoint[1]) < tolerance
) {
// to avoid wrapping, let's only pick the points that inverts back to its original point
return inverted;
}

return null;
};

const retrievePngData = async (pngInput: string | Buffer | PNG) => {
if (typeof pngInput === 'string') {
const pngFile = await readFile(pngInput);
return PNG.sync.read(pngFile);
}

if (typeof pngInput === 'object') {
return pngInput instanceof PNG ? pngInput : PNG.sync.read(pngInput);
}

throw new TypeError('Invalid input argument.');
};

const prepareOutputData = (
projection: Projection,
sourcePng: { width: number, height: number },
options = {} as ProjectOptions,
): PNG => {
const p = buildProjectionFunction(projection, options);
const {
bounds = [[-180, 90], [180, -90]],
} = options;
const nwBoundsRaw = p(bounds[0]);
const seBoundsRaw = p(bounds[1]);
const nwBounds = nwBoundsRaw ? [
(nwBoundsRaw[0] / referenceWidth) * sourcePng.width,
(nwBoundsRaw[1] / referenceHeight) * sourcePng.height,
] : null;

const seBounds = seBoundsRaw ? [
(seBoundsRaw[0] / referenceWidth) * sourcePng.width,
(seBoundsRaw[1] / referenceHeight) * sourcePng.height,
] : null;

let tx = sourcePng.width;
let ty = sourcePng.height;
if (seBounds && nwBounds) {
tx = (nwBounds[0] + seBounds[0]);
ty = (nwBounds[1] + seBounds[1]);

if (
projection[0] === 'Mercator'
&& ty > tx
) {
ty = tx;
}
}

return new PNG({
width: tx,
height: ty,
});
};

export const project = async (
pngInput: string | Buffer | PNG,
projection: Projection,
options?: ProjectOptions,
) => {
const sourcePngData = await retrievePngData(pngInput);
const { width: sx, height: sy, data: sourceData } = sourcePngData;
const outputPngData = prepareOutputData(projection, sourcePngData, options);
const { width: tx, height: ty, data: targetData } = outputPngData;

let i = 0;
for (let y = (sy - ty) / 2; y < (ty + ((sy - ty) / 2)); y += 1) {
for (let x = 0; x < (tx + ((sx - tx) / 2)); x += 1) {
const projected = projectPoint([x, y], projection, {
bounds: options?.bounds,
inputDimensions: {
width: sx,
height: sy,
},
});
if (projected) {
const [lambda, phi] = projected;
if (!(lambda > 180 || lambda < -180 || phi > 90 || phi < -90)) {
// eslint-disable-next-line no-bitwise
const q = (((90 - phi) / 180) * sy | 0) * sx + (((180 + lambda) / 360) * sx | 0) << 2;
targetData[i] = sourceData[q];
targetData[i + 1] = sourceData[q + 1];
targetData[i + 2] = sourceData[q + 2];
targetData[i + 3] = sourceData[q + 3];
}
}
i += 4;
}
}

return PNG.sync.write(outputPngData);
};
export * from './projection';
export * from './geo';

+ 15
- 0
src/png.ts ファイルの表示

@@ -0,0 +1,15 @@
import { PNG } from 'pngjs';
import { readFile } from 'fs/promises';

export const load = async (pngInput: string | Buffer | PNG) => {
if (typeof pngInput === 'string') {
const pngFile = await readFile(pngInput);
return PNG.sync.read(pngFile);
}

if (typeof pngInput === 'object') {
return pngInput instanceof PNG ? pngInput : PNG.sync.read(pngInput);
}

throw new TypeError('Invalid input argument.');
};

+ 302
- 0
src/projection.ts ファイルの表示

@@ -0,0 +1,302 @@
import * as d3geo from 'd3-geo';
import * as d3geoProjection from 'd3-geo-projection';
import * as d3geoPolygon from 'd3-geo-polygon';
import { PNG } from 'pngjs';
import * as Png from './png';

export type Point = [number, number]
export type Bounds = [Point, Point]

type Projection = [string, ...unknown[]]

type Rect = {
width: number,
height: number,
}

export type ProjectOptions = {
bounds: Bounds,
wrapAround: boolean,
outputSize?: Partial<Rect>,
outputPadding?: {
x?: number,
y?: number,
}
}

const geoProjectionNamePrefix = 'geo';

type GeoProjectionFactory = any

const getProjectionFunction = (projectionFunctionName: string): GeoProjectionFactory => {
if (projectionFunctionName in d3geoPolygon) {
return (d3geoPolygon as Record<string, unknown>)[projectionFunctionName];
}
if (projectionFunctionName in d3geoProjection) {
return (d3geoProjection as Record<string, unknown>)[projectionFunctionName];
}
if (projectionFunctionName in d3geo) {
return (d3geo as Record<string, unknown>)[projectionFunctionName];
}

const properProjectionName = projectionFunctionName.slice(
projectionFunctionName.indexOf(geoProjectionNamePrefix)
+ geoProjectionNamePrefix.length,
);

throw new Error(`Unknown projection: ${properProjectionName}`);
};

const buildProjection = (projection: Projection) => {
const [projectionName, ...projectionArgs] = projection;
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
const projectionFunction = getProjectionFunction(`${geoProjectionNamePrefix}${projectionName}`);
// eslint-disable-next-line @typescript-eslint/no-unsafe-call
return projectionFunction(projectionArgs) as d3geo.GeoProjection;
};

const getCenter = (bounds: Bounds): Point => {
const [nw, se] = bounds;
const [nwLng, nwLat] = nw;
const [seLng, seLat] = se;
let seLngNorm = seLng;

while (seLngNorm < nwLng) {
seLngNorm += 360;
}

return [
((((nwLng + 180) + (seLngNorm + 180)) / 2) % 360) - 180,
(nwLat + seLat) / 2,
];
};

const transformGeoProjection = (
geoProjection: d3geo.GeoProjection,
options: ProjectOptions,
inputWidth: number,
) => {
const center = getCenter(options.bounds);
const transformedGeoProjection = geoProjection
.reflectX(false)
.reflectY(false)
.rotate([-center[0], -center[1]]);

const boundsGeoJson: GeoJSON.Polygon = {
type: 'Polygon',
coordinates: [
[
[options.bounds[0][0], options.bounds[0][1]],
[options.bounds[1][0], options.bounds[0][1]],
[options.bounds[1][0], options.bounds[1][1]],
[options.bounds[0][0], options.bounds[1][1]],
],
],
};

if (typeof options.outputSize?.width === 'number') {
if (typeof options.outputSize.height === 'number') {
const paddingX = options.outputPadding?.x ?? 0;
const paddingY = options.outputPadding?.y ?? 0;
return transformedGeoProjection.fitExtent(
[
[paddingX, paddingY],
[options.outputSize.width - paddingX, options.outputSize.height - paddingY],
],
boundsGeoJson,
);
}
return transformedGeoProjection.fitWidth(
options.outputSize.width,
boundsGeoJson,
);
}
if (typeof options.outputSize?.height === 'number') {
return transformedGeoProjection.fitHeight(
options.outputSize.height,
boundsGeoJson,
);
}

return transformedGeoProjection.fitWidth(inputWidth, boundsGeoJson);
};

const computeLatitudeSensitiveProjectionVerticalBounds = (
transformedGeoProjection: d3geo.GeoProjection,
bounds: Bounds,
outputWidthRaw: number,
) => {
// web mercator clipping
// const maxAbsLatitude
// = ((2 * Math.atan(Math.E ** Math.PI) - (Math.PI / 2)) / (Math.PI * 2)) * 360;
const maxAbsLatitude = 85.0511287798066;
const adjustedNwBoundsRaw = transformedGeoProjection([
bounds[0][0],
Math.min(bounds[0][1], maxAbsLatitude),
]);
const adjustedSeBoundsRaw = transformedGeoProjection([
bounds[1][0],
Math.max(bounds[1][1], -maxAbsLatitude),
]);

if (!(adjustedNwBoundsRaw && adjustedSeBoundsRaw)) {
return null;
}

return [
Math.round(outputWidthRaw),
Math.round(adjustedSeBoundsRaw[1] - adjustedNwBoundsRaw[1]),
];
};

const computeLongitudeSensitiveProjectionHorizontalBounds = (
transformedGeoProjection: d3geo.GeoProjection,
bounds: Bounds,
outputHeightRaw: number,
) => {
const adjustedWBoundsRaw = transformedGeoProjection([
bounds[0][0],
(bounds[0][1] + bounds[1][1]) / 2,
]);
const adjustedEBoundsRaw = transformedGeoProjection([
bounds[1][0],
(bounds[0][1] + bounds[1][1]) / 2,
]);

if (!(adjustedWBoundsRaw && adjustedEBoundsRaw)) {
return null;
}

return [
Math.round(adjustedEBoundsRaw[0] - adjustedWBoundsRaw[0]),
Math.round(outputHeightRaw),
];
};

const computeOutputBounds = (
transformedGeoProjection: d3geo.GeoProjection,
projectionName: string,
bounds: Bounds,
outputSize?: Partial<Rect>,
) => {
// TODO: what would it be for polygonal projections?

if (
typeof outputSize?.width === 'number'
&& typeof outputSize.height === 'number'
) {
return [
outputSize.width,
outputSize.height,
];
}

const nwBoundsRaw = transformedGeoProjection(bounds[0]);
const seBoundsRaw = transformedGeoProjection(bounds[1]);

if (!(nwBoundsRaw && seBoundsRaw)) {
return null;
}

const outputWidthRaw = seBoundsRaw[0] - nwBoundsRaw[0];
const outputHeightRaw = seBoundsRaw[1] - nwBoundsRaw[1];

switch (projectionName) {
case 'Mercator':
return computeLatitudeSensitiveProjectionVerticalBounds(
transformedGeoProjection,
bounds,
outputWidthRaw,
);
case 'Robinson':
case 'Sinusoidal':
return computeLongitudeSensitiveProjectionHorizontalBounds(
transformedGeoProjection,
bounds,
outputHeightRaw,
);
default:
break;
}

return [
Math.round(outputWidthRaw),
Math.round(outputHeightRaw),
];
};

export const project = async (
pngInput: string | Buffer | PNG,
projection: Projection,
options = {
wrapAround: false,
bounds: [[-180, 90], [180, -90]],
outputSize: undefined,
} as ProjectOptions,
) => {
const inputPng = await Png.load(pngInput);
const geoProjection = buildProjection(projection);
const [projectionName] = projection;

const transformedGeoProjection = transformGeoProjection(geoProjection, options, inputPng.width);
if (!transformedGeoProjection.invert) {
throw new Error(`No invert() function for projection "${projectionName}"`);
}

const outputBounds = computeOutputBounds(
transformedGeoProjection,
projectionName,
options.bounds,
options.outputSize,
);

if (!outputBounds) {
throw new Error(
`Cannot compute bounds, possibly unimplemented. Check logic of "${projectionName}" projection.`,
);
}

const [outputWidth, outputHeight] = outputBounds;
// outputWidth = options.outputSize?.width ?? 461;
// outputHeight = options.outputSize?.height ?? 461;

const { data: inputData } = inputPng;
const outputPng = new PNG({
width: outputWidth,
height: outputHeight,
});
const { data: outputData } = outputPng;

let i = 0;
for (let y = 0; y < outputHeight; y += 1) {
for (let x = 0; x < outputWidth; x += 1) {
const projected = transformedGeoProjection.invert([x, y]);
if (projected) {
const reversed = transformedGeoProjection(projected);
if (reversed) {
const isSamePoint = (
Math.abs(reversed[0] - x) < 0.5
&& Math.abs(reversed[1] - y) < 0.5
);

if (isSamePoint) {
const [lambda, phi] = projected;
if (!(lambda > 180 || lambda < -180 || phi > 90 || phi < -90)) {
// eslint-disable-next-line no-bitwise
const q = (((90 - phi) / 180) * inputPng.height | 0) * inputPng.width
// eslint-disable-next-line no-bitwise
+ (((180 + lambda) / 360) * inputPng.width | 0) << 2;
outputData[i] = inputData[q];
outputData[i + 1] = inputData[q + 1];
outputData[i + 2] = inputData[q + 2];
outputData[i + 3] = inputData[q + 3];
}
}
}
}
i += 4;
}
}

return PNG.sync.write(outputPng);
};

+ 2
- 1
tsconfig.json ファイルの表示

@@ -16,6 +16,7 @@
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "ES2017"
"target": "ES2017",
"resolveJsonModule": true
}
}

+ 22
- 0
tsconfig.script.json ファイルの表示

@@ -0,0 +1,22 @@
{
"exclude": ["node_modules"],
"include": ["src", "types"],
"compilerOptions": {
"module": "CommonJS",
"lib": ["ESNext", "DOM"],
"importHelpers": true,
"declaration": true,
"sourceMap": true,
"rootDir": "./src",
"strict": false,
"noUnusedLocals": true,
"noUnusedParameters": true,
"noImplicitReturns": true,
"noFallthroughCasesInSwitch": true,
"moduleResolution": "node",
"jsx": "react",
"esModuleInterop": true,
"target": "ES2017",
"resolveJsonModule": true
}
}

+ 87
- 1
yarn.lock ファイルの表示

@@ -234,6 +234,18 @@
"@babel/helper-validator-identifier" "^7.16.7"
to-fast-properties "^2.0.0"
"@cspotcode/source-map-consumer@0.8.0":
version "0.8.0"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-consumer/-/source-map-consumer-0.8.0.tgz#33bf4b7b39c178821606f669bbc447a6a629786b"
integrity sha512-41qniHzTU8yAGbCp04ohlmSrZf8bkf/iJsl3V0dRGsQN/5GFfx+LbCSsCpp2gqrqjTVg/K6O8ycoV35JIwAzAg==
"@cspotcode/source-map-support@0.7.0":
version "0.7.0"
resolved "https://registry.yarnpkg.com/@cspotcode/source-map-support/-/source-map-support-0.7.0.tgz#4789840aa859e46d2f3173727ab707c66bf344f5"
integrity sha512-X4xqRHqN8ACt2aHVe51OxeA2HjbcL4MqFqXkrmQszJ1NOUuUu5u6Vqx/0lZSVNku7velL5FC/s5uEAj1lsBMhA==
dependencies:
"@cspotcode/source-map-consumer" "0.8.0"
"@eslint/eslintrc@^1.2.1":
version "1.2.1"
resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-1.2.1.tgz#8b5e1c49f4077235516bc9ec7d41378c0f69b8c6"
@@ -324,6 +336,26 @@
resolved "https://registry.yarnpkg.com/@ovyerus/licenses/-/licenses-6.4.4.tgz#596e3ace46ab7c70bcf0e2b17f259796a4bedf9f"
integrity sha512-IHjc31WXciQT3hfvdY+M59jBkQp70Fpr04tNDVO5rez2PNv4u8tE6w//CkU+GeBoO9k2ahneSqzjzvlgjyjkGw==
"@tsconfig/node10@^1.0.7":
version "1.0.8"
resolved "https://registry.yarnpkg.com/@tsconfig/node10/-/node10-1.0.8.tgz#c1e4e80d6f964fbecb3359c43bd48b40f7cadad9"
integrity sha512-6XFfSQmMgq0CFLY1MslA/CPUfhIL919M1rMsa5lP2P097N2Wd1sSX0tx1u4olM16fLNhtHZpRhedZJphNJqmZg==
"@tsconfig/node12@^1.0.7":
version "1.0.9"
resolved "https://registry.yarnpkg.com/@tsconfig/node12/-/node12-1.0.9.tgz#62c1f6dee2ebd9aead80dc3afa56810e58e1a04c"
integrity sha512-/yBMcem+fbvhSREH+s14YJi18sp7J9jpuhYByADT2rypfajMZZN4WQ6zBGgBKp53NKmqI36wFYDb3yaMPurITw==
"@tsconfig/node14@^1.0.0":
version "1.0.1"
resolved "https://registry.yarnpkg.com/@tsconfig/node14/-/node14-1.0.1.tgz#95f2d167ffb9b8d2068b0b235302fafd4df711f2"
integrity sha512-509r2+yARFfHHE7T6Puu2jjkoycftovhXRqW328PDXTVGKihlb1P8Z9mMZH04ebyajfRY7dedfGynlrFHJUQCg==
"@tsconfig/node16@^1.0.2":
version "1.0.2"
resolved "https://registry.yarnpkg.com/@tsconfig/node16/-/node16-1.0.2.tgz#423c77877d0569db20e1fc80885ac4118314010e"
integrity sha512-eZxlbI8GZscaGS7kkc/trHTT5xgrjH3/1n2JDwusC9iahPKWMRvRjJSAN5mCXviuTGQ/lHnhvv8Q1YTpnfz9gA==
"@types/chai-subset@^1.3.3":
version "1.3.3"
resolved "https://registry.yarnpkg.com/@types/chai-subset/-/chai-subset-1.3.3.tgz#97893814e92abd2c534de422cb377e0e0bdaac94"
@@ -672,7 +704,12 @@ acorn-jsx@^5.3.1:
resolved "https://registry.yarnpkg.com/acorn-jsx/-/acorn-jsx-5.3.2.tgz#7ed5bb55908b3b2f1bc55c6af1653bada7f07937"
integrity sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==
acorn@^8.7.0:
acorn-walk@^8.1.1:
version "8.2.0"
resolved "https://registry.yarnpkg.com/acorn-walk/-/acorn-walk-8.2.0.tgz#741210f2e2426454508853a2f44d0ab83b7f69c1"
integrity sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==
acorn@^8.4.1, acorn@^8.7.0:
version "8.7.0"
resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.7.0.tgz#90951fde0f8f09df93549481e5fc141445b791cf"
integrity sha512-V/LGr1APy+PXIwKebEWrkZPwoeoF+w1jiOBUmuxuiUIaOHtob8Qc9BTrYo7VuI5fR8tqsy+buA2WFooR5olqvQ==
@@ -729,6 +766,11 @@ are-we-there-yet@~1.1.2:
delegates "^1.0.0"
readable-stream "^2.0.6"
arg@^4.1.0:
version "4.1.3"
resolved "https://registry.yarnpkg.com/arg/-/arg-4.1.3.tgz#269fc7ad5b8e42cb63c896d5666017261c144089"
integrity sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==
argparse@^2.0.1:
version "2.0.1"
resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38"
@@ -1075,6 +1117,11 @@ core-util-is@~1.0.0:
resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.3.tgz#a6042d3634c2b27e9328f837b965fac83808db85"
integrity sha512-ZQBvi1DcpJ4GDqanjucZ2Hj3wEO5pZDS89BWbkcrvdxksJorwUDDZamX9ldFkp9aw2lmBDLgkObEA4DWNJ9FYQ==
create-require@^1.1.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@^7.0.2, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
@@ -1460,6 +1507,11 @@ detect-libc@^2.0.0, detect-libc@^2.0.1:
resolved "https://registry.yarnpkg.com/detect-libc/-/detect-libc-2.0.1.tgz#e1897aa88fa6ad197862937fbc0441ef352ee0cd"
integrity sha512-463v3ZeIrcWtdgIg6vI6XUncguvr2TnGl4SzDXinkt9mSLpBJKXT3mW6xT3VQdDN11+WVs29pgvivTc4Lp8v+w==
diff@^4.0.1:
version "4.0.2"
resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.2.tgz#60f3aecb89d5fae520c11aa19efc2bb982aade7d"
integrity sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==
dir-glob@^3.0.1:
version "3.0.1"
resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f"
@@ -2694,6 +2746,11 @@ make-dir@^3.0.0:
dependencies:
semver "^6.0.0"
make-error@^1.1.1:
version "1.3.6"
resolved "https://registry.yarnpkg.com/make-error/-/make-error-1.3.6.tgz#2eb2e37ea9b67c4891f684a1394799af484cf7a2"
integrity sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==
merge-stream@^2.0.0:
version "2.0.0"
resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60"
@@ -3556,6 +3613,25 @@ to-regex-range@^5.0.1:
dependencies:
is-number "^7.0.0"
ts-node@^10.7.0:
version "10.7.0"
resolved "https://registry.yarnpkg.com/ts-node/-/ts-node-10.7.0.tgz#35d503d0fab3e2baa672a0e94f4b40653c2463f5"
integrity sha512-TbIGS4xgJoX2i3do417KSaep1uRAW/Lu+WAL2doDHC0D6ummjirVOXU5/7aiZotbQ5p1Zp9tP7U6cYhA0O7M8A==
dependencies:
"@cspotcode/source-map-support" "0.7.0"
"@tsconfig/node10" "^1.0.7"
"@tsconfig/node12" "^1.0.7"
"@tsconfig/node14" "^1.0.0"
"@tsconfig/node16" "^1.0.2"
acorn "^8.4.1"
acorn-walk "^8.1.1"
arg "^4.1.0"
create-require "^1.1.0"
diff "^4.0.1"
make-error "^1.1.1"
v8-compile-cache-lib "^3.0.0"
yn "3.1.1"
tsconfig-paths@^3.14.1:
version "3.14.1"
resolved "https://registry.yarnpkg.com/tsconfig-paths/-/tsconfig-paths-3.14.1.tgz#ba0734599e8ea36c862798e920bcf163277b137a"
@@ -3653,6 +3729,11 @@ util-deprecate@^1.0.1, util-deprecate@~1.0.1:
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
v8-compile-cache-lib@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.0.tgz#0582bcb1c74f3a2ee46487ceecf372e46bce53e8"
integrity sha512-mpSYqfsFvASnSn5qMiwrr4VKfumbPyONLCOPmsR3A6pTY/r0+tSaVbgPWSAIuzbk3lCTa+FForeTiO+wBQGkjA==
v8-compile-cache@^2.0.3:
version "2.3.0"
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.3.0.tgz#2de19618c66dc247dcfb6f99338035d8245a2cee"
@@ -3839,6 +3920,11 @@ yargs@^17.2.1:
y18n "^5.0.5"
yargs-parser "^21.0.0"
yn@3.1.1:
version "3.1.1"
resolved "https://registry.yarnpkg.com/yn/-/yn-3.1.1.tgz#1e87401a09d767c1d5eab26a6e4c185182d2eb50"
integrity sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==
yocto-queue@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"


読み込み中…
キャンセル
保存