fix: refactor duplicate utils into js-utils, export symbols
BREAKING CHANGE: extract typed errors and use the equivalent from js-utils
This commit is contained in:
parent
bbd354d2e2
commit
859baa33f9
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [CONFIG\_SCHEMA](./js-yaml-schema.config_schema.md)
|
||||||
|
|
||||||
|
## CONFIG\_SCHEMA variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
CONFIG_SCHEMA: Schema
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [envType](./js-yaml-schema.envtype.md)
|
||||||
|
|
||||||
|
## envType variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
envType: YamlType
|
||||||
|
```
|
|
@ -0,0 +1,13 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [includeSchema](./js-yaml-schema.includeschema.md)
|
||||||
|
|
||||||
|
## includeSchema variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
includeSchema: {
|
||||||
|
schema: import("js-yaml").Schema;
|
||||||
|
}
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [includeType](./js-yaml-schema.includetype.md)
|
||||||
|
|
||||||
|
## includeType variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
includeType: YamlType
|
||||||
|
```
|
|
@ -4,3 +4,14 @@
|
||||||
|
|
||||||
## js-yaml-schema package
|
## js-yaml-schema package
|
||||||
|
|
||||||
|
## Variables
|
||||||
|
|
||||||
|
| Variable | Description |
|
||||||
|
| --- | --- |
|
||||||
|
| [CONFIG\_SCHEMA](./js-yaml-schema.config_schema.md) | |
|
||||||
|
| [envType](./js-yaml-schema.envtype.md) | |
|
||||||
|
| [includeSchema](./js-yaml-schema.includeschema.md) | |
|
||||||
|
| [includeType](./js-yaml-schema.includetype.md) | |
|
||||||
|
| [regexpType](./js-yaml-schema.regexptype.md) | |
|
||||||
|
| [streamType](./js-yaml-schema.streamtype.md) | |
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [regexpType](./js-yaml-schema.regexptype.md)
|
||||||
|
|
||||||
|
## regexpType variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
regexpType: YamlType
|
||||||
|
```
|
|
@ -0,0 +1,11 @@
|
||||||
|
<!-- Do not edit this file. It is automatically generated by API Documenter. -->
|
||||||
|
|
||||||
|
[Home](./index.md) > [@apextoaster/js-yaml-schema](./js-yaml-schema.md) > [streamType](./js-yaml-schema.streamtype.md)
|
||||||
|
|
||||||
|
## streamType variable
|
||||||
|
|
||||||
|
<b>Signature:</b>
|
||||||
|
|
||||||
|
```typescript
|
||||||
|
streamType: YamlType
|
||||||
|
```
|
|
@ -11,6 +11,7 @@
|
||||||
"author": "ssube",
|
"author": "ssube",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@apextoaster/js-utils": "^0.1.1",
|
||||||
"@istanbuljs/nyc-config-typescript": "1.0.1",
|
"@istanbuljs/nyc-config-typescript": "1.0.1",
|
||||||
"@microsoft/api-documenter": "7.7.15",
|
"@microsoft/api-documenter": "7.7.15",
|
||||||
"@microsoft/api-extractor": "7.7.10",
|
"@microsoft/api-extractor": "7.7.10",
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
import { BaseError } from 'noicejs';
|
|
||||||
|
|
||||||
export class InvalidArgumentError extends BaseError {
|
|
||||||
constructor(msg = 'invalid argument passed', ...nested: Array<Error>) {
|
|
||||||
super(msg, ...nested);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,7 +0,0 @@
|
||||||
import { BaseError } from 'noicejs';
|
|
||||||
|
|
||||||
export class NotFoundError extends BaseError {
|
|
||||||
constructor(msg = 'value not found', ...nested: Array<Error>) {
|
|
||||||
super(msg, ...nested);
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,5 +1,11 @@
|
||||||
import { main } from './app';
|
import { main } from './app';
|
||||||
|
|
||||||
|
export { CONFIG_SCHEMA } from './schema';
|
||||||
|
export { envType } from './type/Env';
|
||||||
|
export { includeSchema, includeType } from './type/Include';
|
||||||
|
export { regexpType } from './type/Regexp';
|
||||||
|
export { streamType } from './type/Stream';
|
||||||
|
|
||||||
const STATUS_ERROR = 1;
|
const STATUS_ERROR = 1;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
import { DEFAULT_SAFE_SCHEMA, Schema } from 'js-yaml';
|
import { DEFAULT_SAFE_SCHEMA, Schema } from 'js-yaml';
|
||||||
|
|
||||||
import { envType } from './type/Env';
|
import { envType } from './type/Env';
|
||||||
import { includeType } from './type/Include';
|
import { includeSchema, includeType } from './type/Include';
|
||||||
import { regexpType } from './type/Regexp';
|
import { regexpType } from './type/Regexp';
|
||||||
import { streamType } from './type/Stream';
|
import { streamType } from './type/Stream';
|
||||||
|
|
||||||
|
@ -11,3 +11,5 @@ export const CONFIG_SCHEMA = Schema.create([DEFAULT_SAFE_SCHEMA], [
|
||||||
regexpType,
|
regexpType,
|
||||||
streamType,
|
streamType,
|
||||||
]);
|
]);
|
||||||
|
|
||||||
|
includeSchema.schema = CONFIG_SCHEMA;
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
import { NotFoundError } from '@apextoaster/js-utils';
|
||||||
import { Type as YamlType } from 'js-yaml';
|
import { Type as YamlType } from 'js-yaml';
|
||||||
|
|
||||||
import { NotFoundError } from '../error/NotFoundError';
|
|
||||||
|
|
||||||
export const envType = new YamlType('!env', {
|
export const envType = new YamlType('!env', {
|
||||||
kind: 'scalar',
|
kind: 'scalar',
|
||||||
resolve(name: string) {
|
resolve(name: string) {
|
||||||
|
|
|
@ -1,10 +1,8 @@
|
||||||
|
import { InvalidArgumentError, NotFoundError } from '@apextoaster/js-utils';
|
||||||
import { existsSync, readFileSync, realpathSync } from 'fs';
|
import { existsSync, readFileSync, realpathSync } from 'fs';
|
||||||
import { SAFE_SCHEMA, safeLoad, Type as YamlType } from 'js-yaml';
|
import { SAFE_SCHEMA, safeLoad, Type as YamlType } from 'js-yaml';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { InvalidArgumentError } from '../error/InvalidArgumentError';
|
|
||||||
import { NotFoundError } from '../error/NotFoundError';
|
|
||||||
|
|
||||||
// work around the circular dependency by setting the schema later
|
// work around the circular dependency by setting the schema later
|
||||||
export const includeSchema = {
|
export const includeSchema = {
|
||||||
schema: SAFE_SCHEMA,
|
schema: SAFE_SCHEMA,
|
||||||
|
|
|
@ -1,8 +1,7 @@
|
||||||
|
import { InvalidArgumentError } from '@apextoaster/js-utils';
|
||||||
import { Type as YamlType } from 'js-yaml';
|
import { Type as YamlType } from 'js-yaml';
|
||||||
import { isNil } from 'lodash';
|
import { isNil } from 'lodash';
|
||||||
|
|
||||||
import { InvalidArgumentError } from '../error/InvalidArgumentError';
|
|
||||||
|
|
||||||
export const REGEXP_REGEXP = /^\/(.+)\/([gimsuy]*)$/;
|
export const REGEXP_REGEXP = /^\/(.+)\/([gimsuy]*)$/;
|
||||||
|
|
||||||
export const regexpType = new YamlType('!regexp', {
|
export const regexpType = new YamlType('!regexp', {
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
|
import { NotFoundError } from '@apextoaster/js-utils';
|
||||||
import { Type as YamlType } from 'js-yaml';
|
import { Type as YamlType } from 'js-yaml';
|
||||||
|
|
||||||
import { NotFoundError } from '../error/NotFoundError';
|
|
||||||
|
|
||||||
const ALLOWED_STREAMS = new Set([
|
const ALLOWED_STREAMS = new Set([
|
||||||
'stdout',
|
'stdout',
|
||||||
'stderr',
|
'stderr',
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
import { AsyncHook, createHook } from 'async_hooks';
|
|
||||||
|
|
||||||
// this will pull Mocha internals out of the stacks
|
|
||||||
/* eslint-disable-next-line @typescript-eslint/no-var-requires */
|
|
||||||
const { stackTraceFilter } = require('mocha/lib/utils');
|
|
||||||
const filterStack = stackTraceFilter();
|
|
||||||
|
|
||||||
type AsyncMochaTest = (this: Mocha.Context | void) => Promise<void>;
|
|
||||||
type AsyncMochaSuite = (this: Mocha.Suite) => Promise<void>;
|
|
||||||
|
|
||||||
/* eslint-disable-next-line @typescript-eslint/ban-types */
|
|
||||||
function isNil<T>(val: T | null | undefined): val is null | undefined {
|
|
||||||
/* eslint-disable-next-line no-null/no-null */
|
|
||||||
return val === null || val === undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface TrackedResource {
|
|
||||||
source: string;
|
|
||||||
triggerAsyncId: number;
|
|
||||||
type: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
function debugMode() {
|
|
||||||
return Reflect.has(process.env, 'DEBUG');
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Async resource tracker using node's internal hooks.
|
|
||||||
*
|
|
||||||
* This probably won't work in a browser. It does not hold references to the resource, to avoid leaks.
|
|
||||||
* Adapted from https://gist.github.com/boneskull/7fe75b63d613fa940db7ec990a5f5843#file-async-dump-js
|
|
||||||
*/
|
|
||||||
export class Tracker {
|
|
||||||
public static getStack(): string {
|
|
||||||
const err = new Error();
|
|
||||||
if (isNil(err.stack)) {
|
|
||||||
return 'no stack trace available';
|
|
||||||
} else {
|
|
||||||
return filterStack(err.stack);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private readonly hook: AsyncHook;
|
|
||||||
private readonly resources: Map<number, TrackedResource>;
|
|
||||||
|
|
||||||
constructor() {
|
|
||||||
this.resources = new Map();
|
|
||||||
this.hook = createHook({
|
|
||||||
destroy: (id: number) => {
|
|
||||||
this.resources.delete(id);
|
|
||||||
},
|
|
||||||
init: (id: number, type: string, triggerAsyncId: number) => {
|
|
||||||
const source = Tracker.getStack();
|
|
||||||
// @TODO: exclude async hooks, including this one
|
|
||||||
this.resources.set(id, {
|
|
||||||
source,
|
|
||||||
triggerAsyncId,
|
|
||||||
type,
|
|
||||||
});
|
|
||||||
},
|
|
||||||
promiseResolve: (id: number) => {
|
|
||||||
this.resources.delete(id);
|
|
||||||
},
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public clear() {
|
|
||||||
this.resources.clear();
|
|
||||||
}
|
|
||||||
|
|
||||||
public disable() {
|
|
||||||
this.hook.disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
/* eslint-disable no-console, no-invalid-this */
|
|
||||||
public dump() {
|
|
||||||
console.error(`tracking ${this.resources.size} async resources`);
|
|
||||||
this.resources.forEach((res, id) => {
|
|
||||||
console.error(`${id}: ${res.type}`);
|
|
||||||
if (debugMode()) {
|
|
||||||
console.error(res.source);
|
|
||||||
console.error('\n');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
public enable() {
|
|
||||||
this.hook.enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public get size(): number {
|
|
||||||
return this.resources.size;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Describe a suite of async tests. This wraps mocha's describe to track async resources and report leaks.
|
|
||||||
*/
|
|
||||||
export function describeLeaks(description: string, cb: AsyncMochaSuite): Mocha.Suite {
|
|
||||||
return describe(description, function trackSuite(this: Mocha.Suite) {
|
|
||||||
const tracker = new Tracker();
|
|
||||||
|
|
||||||
beforeEach(() => {
|
|
||||||
tracker.enable();
|
|
||||||
});
|
|
||||||
|
|
||||||
afterEach(() => {
|
|
||||||
tracker.disable();
|
|
||||||
const leaked = tracker.size;
|
|
||||||
|
|
||||||
// @TODO: this should only exclude the single Immediate set by the Tracker
|
|
||||||
if (leaked > 1) {
|
|
||||||
tracker.dump();
|
|
||||||
const msg = `test leaked ${leaked - 1} async resources`;
|
|
||||||
if (debugMode()) {
|
|
||||||
throw new Error(msg);
|
|
||||||
} else {
|
|
||||||
/* eslint-disable-next-line no-console */
|
|
||||||
console.warn(msg);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
tracker.clear();
|
|
||||||
});
|
|
||||||
|
|
||||||
const suite: PromiseLike<void> | undefined = cb.call(this);
|
|
||||||
if (isNil(suite) || !Reflect.has(suite, 'then')) {
|
|
||||||
/* eslint-disable-next-line no-console */
|
|
||||||
console.error(`test suite '${description}' did not return a promise`);
|
|
||||||
}
|
|
||||||
|
|
||||||
return suite;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Run an asynchronous test with unhandled rejection guards.
|
|
||||||
*
|
|
||||||
* This function may not have any direct test coverage. It is too simple to reasonably mock.
|
|
||||||
*/
|
|
||||||
export function itLeaks(expectation: string, cb?: AsyncMochaTest): Mocha.Test {
|
|
||||||
if (isNil(cb)) {
|
|
||||||
return it(expectation);
|
|
||||||
}
|
|
||||||
|
|
||||||
return it(expectation, function trackTest(this: Mocha.Context) {
|
|
||||||
return new Promise<unknown>((res, rej) => {
|
|
||||||
cb.call(this).then((value: unknown) => {
|
|
||||||
res(value);
|
|
||||||
}, (err: Error) => {
|
|
||||||
rej(err);
|
|
||||||
});
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,22 +1,21 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import { NotFoundError } from '../../src/error/NotFoundError';
|
import { NotFoundError } from '@apextoaster/js-utils';
|
||||||
import { envType } from '../../src/type/Env';
|
import { envType } from '../../src/type/Env';
|
||||||
import { VERSION_INFO } from '../../src/version';
|
import { VERSION_INFO } from '../../src/version';
|
||||||
import { describeLeaks, itLeaks } from '../helpers/async';
|
|
||||||
|
|
||||||
describeLeaks('env config type', async () => {
|
describe('env config type', async () => {
|
||||||
itLeaks('should throw on missing variables', async () => {
|
it('should throw on missing variables', async () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
envType.resolve('DOES_NOT_EXIST_');
|
envType.resolve('DOES_NOT_EXIST_');
|
||||||
}).to.throw(NotFoundError);
|
}).to.throw(NotFoundError);
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should resolve existing variables', async () => {
|
it('should resolve existing variables', async () => {
|
||||||
expect(envType.resolve('CI_COMMIT_SHA')).to.equal(true);
|
expect(envType.resolve('CI_COMMIT_SHA')).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should construct a value from variables', async () => {
|
it('should construct a value from variables', async () => {
|
||||||
expect(envType.construct('CI_COMMIT_SHA')).to.equal(VERSION_INFO.git.commit);
|
expect(envType.construct('CI_COMMIT_SHA')).to.equal(VERSION_INFO.git.commit);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,29 +1,27 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
import { join } from 'path';
|
import { join } from 'path';
|
||||||
|
|
||||||
import { InvalidArgumentError } from '../../src/error/InvalidArgumentError';
|
import { InvalidArgumentError, NotFoundError } from '@apextoaster/js-utils';
|
||||||
import { NotFoundError } from '../../src/error/NotFoundError';
|
|
||||||
import { includeType } from '../../src/type/Include';
|
import { includeType } from '../../src/type/Include';
|
||||||
import { describeLeaks, itLeaks } from '../helpers/async';
|
|
||||||
|
|
||||||
const TEST_ROOT = '../test/type';
|
const TEST_ROOT = '../test/type';
|
||||||
|
|
||||||
describeLeaks('include config type', async () => {
|
describe('include config type', async () => {
|
||||||
itLeaks('should resolve existing files', async () => {
|
it('should resolve existing files', async () => {
|
||||||
expect(includeType.resolve(join(TEST_ROOT, 'include.yml'))).to.equal(true);
|
expect(includeType.resolve(join(TEST_ROOT, 'include.yml'))).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should throw when resolving missing files', async () => {
|
it('should throw when resolving missing files', async () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
includeType.resolve(join(TEST_ROOT, 'missing.yml'));
|
includeType.resolve(join(TEST_ROOT, 'missing.yml'));
|
||||||
}).to.throw(NotFoundError);
|
}).to.throw(NotFoundError);
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should construct data from file', async () => {
|
it('should construct data from file', async () => {
|
||||||
expect(includeType.construct(join(TEST_ROOT, 'include.yml'))).to.equal('test');
|
expect(includeType.construct(join(TEST_ROOT, 'include.yml'))).to.equal('test');
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should throw when constructing missing files', async () => {
|
it('should throw when constructing missing files', async () => {
|
||||||
expect(() => {
|
expect(() => {
|
||||||
includeType.construct(join(TEST_ROOT, 'missing.yml'));
|
includeType.construct(join(TEST_ROOT, 'missing.yml'));
|
||||||
}).to.throw(InvalidArgumentError);
|
}).to.throw(InvalidArgumentError);
|
||||||
|
|
|
@ -1,27 +1,26 @@
|
||||||
import { expect } from 'chai';
|
import { expect } from 'chai';
|
||||||
|
|
||||||
import { regexpType } from '../../src/type/Regexp';
|
import { regexpType } from '../../src/type/Regexp';
|
||||||
import { describeLeaks, itLeaks } from '../helpers/async';
|
|
||||||
|
|
||||||
describeLeaks('regexp config type', async () => {
|
describe('regexp config type', async () => {
|
||||||
itLeaks('match slashed strings', async () => {
|
it('match slashed strings', async () => {
|
||||||
expect(regexpType.resolve('/foo/')).to.equal(true);
|
expect(regexpType.resolve('/foo/')).to.equal(true);
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should match flags', async () => {
|
it('should match flags', async () => {
|
||||||
const regexp: RegExp = regexpType.construct('/foo/g');
|
const regexp: RegExp = regexpType.construct('/foo/g');
|
||||||
expect(regexp.flags).to.equal('g');
|
expect(regexp.flags).to.equal('g');
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should not match bare strings', async () => {
|
it('should not match bare strings', async () => {
|
||||||
expect(regexpType.resolve('foo')).to.equal(false);
|
expect(regexpType.resolve('foo')).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should not match invalid flags', async () => {
|
it('should not match invalid flags', async () => {
|
||||||
expect(regexpType.resolve('/foo/notrealflags')).to.equal(false);
|
expect(regexpType.resolve('/foo/notrealflags')).to.equal(false);
|
||||||
});
|
});
|
||||||
|
|
||||||
itLeaks('should not match regex embedded in a longer string', async () => {
|
it('should not match regex embedded in a longer string', async () => {
|
||||||
expect(regexpType.resolve('some/regex/with-padding')).to.equal(false);
|
expect(regexpType.resolve('some/regex/with-padding')).to.equal(false);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
|
@ -2,6 +2,11 @@
|
||||||
# yarn lockfile v1
|
# yarn lockfile v1
|
||||||
|
|
||||||
|
|
||||||
|
"@apextoaster/js-utils@^0.1.1":
|
||||||
|
version "0.1.1"
|
||||||
|
resolved "https://artifacts.apextoaster.com/repository/group-npm/@apextoaster/js-utils/-/js-utils-0.1.1.tgz#035548ce76f12c1de4b9c20f9b9aeebd0c840546"
|
||||||
|
integrity sha512-hJZY3smbpTPdKidZIaa+VDROkCIjaEahhPqqF7YCqvFP5E/CNbwbiNqASxZjz97Dde2Dw6II8YGDV5Ef8yfO3g==
|
||||||
|
|
||||||
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5":
|
"@babel/code-frame@^7.0.0", "@babel/code-frame@^7.5.5":
|
||||||
version "7.5.5"
|
version "7.5.5"
|
||||||
resolved "https://artifacts.apextoaster.com/repository/group-npm/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
|
resolved "https://artifacts.apextoaster.com/repository/group-npm/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d"
|
||||||
|
|
Loading…
Reference in New Issue