Compare commits
17 Commits
Author | SHA1 | Date | |
---|---|---|---|
73e7f64860 | |||
e17e1650d5 | |||
3ecb63d500 | |||
41ee7e90ef | |||
c70bba727e | |||
747248454d | |||
59386241b4 | |||
c70b9b0dd1 | |||
2ee00ed919 | |||
cbfc271da5 | |||
d45b492837 | |||
ed54c145b7 | |||
64ed9a6044 | |||
75267abd91 | |||
ba9a3992b7 | |||
a74c32ed6d | |||
c5f9812acc |
20
CHANGELOG.md
20
CHANGELOG.md
@ -1,3 +1,23 @@
|
||||
### **4.2.6** (2021-11-08)
|
||||
|
||||
- Fix deepClone so we can overwrite with undefined in when we mock kcContext
|
||||
|
||||
### **4.2.5** (2021-11-07)
|
||||
|
||||
- Better debugging experience with user profile
|
||||
|
||||
### **4.2.4** (2021-11-01)
|
||||
|
||||
- Better autoComplete typings
|
||||
|
||||
### **4.2.3** (2021-11-01)
|
||||
|
||||
- Make it more easy to understand that error in the log are expected
|
||||
|
||||
### **4.2.2** (2021-10-27)
|
||||
|
||||
- Replace 'path' by 'browserify-path' #47
|
||||
|
||||
### **4.2.1** (2021-10-26)
|
||||
|
||||
- useFormValidationSlice: update when params have changed
|
||||
|
16
README.md
16
README.md
@ -444,18 +444,20 @@ The logs of your keycloak server will always show this kind of errors every time
|
||||
|
||||
```log
|
||||
FTL stack trace ("~" means nesting-related):
|
||||
- Failed at: #local value = object[key] [in template "login.ftl" in macro "objectToJson" at line 70, column 21]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson" at line 36, column 5]
|
||||
- Reached through: @objectToJson object=value depth=(dep... [in template "login.ftl" in macro "objectToJson" at line 81, column 27]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson" at line 36, column 5]
|
||||
- Reached through: @objectToJson object=(.data_model) de... [in template "login.ftl" at line 163, column 43]
|
||||
- Failed at: #local value = object[key] [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 70, column 21]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 36, column 5]
|
||||
- Reached through: @objectToJson_please_ignore_errors object=value depth=(dep... [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 81, column 27]
|
||||
- Reached through: @compress [in template "login.ftl" in macro "objectToJson_please_ignore_errors" at line 36, column 5]
|
||||
- Reached through: @objectToJson_please_ignore_errors object=(.data_model) de... [in template "login.ftl" at line 163, column 43]
|
||||
```
|
||||
|
||||
Theses are expected and can be safely ignored.
|
||||
Theses are expected to show up in the log.
|
||||
Unfortunately, there is nothing I know of that can be done to avoid them or even mute them.
|
||||
They can be, however, safely ignored.
|
||||
|
||||
To [converts the `.ftl` values into a JavaScript object](https://github.com/InseeFrLab/keycloakify/blob/main/src/bin/build-keycloak-theme/generateFtl/common.ftl)
|
||||
without making assumptions on the `.data_model` we have to do things that throws.
|
||||
It's all-right though because every statement that can fail is inside an `<#attempt><#recorver>` block but it results in errors being printed to the logs.
|
||||
It's all-right because every statement that can fail is inside an `<#attempt><#recorver>` block but it results in errors being printed to the logs.
|
||||
|
||||
# Adding custom message (to `i18n/useKcMessage.tsx`)
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "keycloakify",
|
||||
"version": "4.2.1",
|
||||
"version": "4.2.6",
|
||||
"description": "Keycloak theme generator for Reacts app",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
@ -79,7 +79,7 @@
|
||||
"cheerio": "^1.0.0-rc.5",
|
||||
"evt": "2.0.0-beta.38",
|
||||
"minimal-polyfills": "^2.2.1",
|
||||
"path": "^0.12.7",
|
||||
"path-browserify": "^1.0.1",
|
||||
"react-markdown": "^5.0.3",
|
||||
"scripting-tools": "^0.19.13",
|
||||
"tsafe": "^0.8.1"
|
||||
|
@ -1,5 +1,5 @@
|
||||
<script>const _=
|
||||
<#macro objectToJson object depth>
|
||||
<#macro objectToJson_please_ignore_errors object depth>
|
||||
<@compress>
|
||||
|
||||
<#local isHash = false>
|
||||
@ -45,7 +45,7 @@
|
||||
<#continue>
|
||||
</#if>
|
||||
|
||||
"${key}": <@objectToJson object=value depth=depth+1/>,
|
||||
"${key}": <@objectToJson_please_ignore_errors object=value depth=depth+1/>,
|
||||
|
||||
</#list>
|
||||
|
||||
@ -102,7 +102,7 @@
|
||||
|
||||
<#list object as item>
|
||||
|
||||
<@objectToJson object=item depth=depth+1/>,
|
||||
<@objectToJson_please_ignore_errors object=item depth=depth+1/>,
|
||||
|
||||
</#list>
|
||||
|
||||
@ -194,7 +194,7 @@
|
||||
Object.deepAssign(
|
||||
out,
|
||||
//Removing all the undefined
|
||||
JSON.parse(JSON.stringify(<@objectToJson object=.data_model depth=0 />))
|
||||
JSON.parse(JSON.stringify(<@objectToJson_please_ignore_errors object=.data_model depth=0 />))
|
||||
);
|
||||
|
||||
Object.deepAssign(
|
||||
|
@ -149,15 +149,6 @@ const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange,
|
||||
</div>
|
||||
<div className={cx(props.kcInputWrapperClass)}>
|
||||
<input
|
||||
autoComplete={(() => {
|
||||
switch (attribute.name) {
|
||||
case "password-confirm":
|
||||
case "password":
|
||||
return "new-password";
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
})()}
|
||||
type={(() => {
|
||||
switch (attribute.name) {
|
||||
case "password-confirm":
|
||||
@ -174,11 +165,7 @@ const UserProfileFormFields = memo(({ kcContext, onIsFormSubmittableValueChange,
|
||||
className={cx(props.kcInputClass)}
|
||||
aria-invalid={displayableErrors.length !== 0}
|
||||
disabled={attribute.readOnly}
|
||||
{...(attribute.autocomplete === undefined
|
||||
? {}
|
||||
: {
|
||||
"autoComplete": attribute.autocomplete,
|
||||
})}
|
||||
autoComplete={attribute.autocomplete}
|
||||
onBlur={onBlurFactory(attribute.name)}
|
||||
/>
|
||||
{displayableErrors.length !== 0 && (
|
||||
|
@ -217,10 +217,64 @@ export type Attribute = {
|
||||
groupDisplayHeader?: string;
|
||||
groupDisplayDescription?: string;
|
||||
readOnly: boolean;
|
||||
autocomplete?: string;
|
||||
validators: Validators;
|
||||
annotations: Record<string, string>;
|
||||
groupAnnotations: Record<string, string>;
|
||||
autocomplete?:
|
||||
| "on"
|
||||
| "off"
|
||||
| "name"
|
||||
| "honorific-prefix"
|
||||
| "given-name"
|
||||
| "additional-name"
|
||||
| "family-name"
|
||||
| "honorific-suffix"
|
||||
| "nickname"
|
||||
| "email"
|
||||
| "username"
|
||||
| "new-password"
|
||||
| "current-password"
|
||||
| "one-time-code"
|
||||
| "organization-title"
|
||||
| "organization"
|
||||
| "street-address"
|
||||
| "address-line1"
|
||||
| "address-line2"
|
||||
| "address-line3"
|
||||
| "address-level4"
|
||||
| "address-level3"
|
||||
| "address-level2"
|
||||
| "address-level1"
|
||||
| "country"
|
||||
| "country-name"
|
||||
| "postal-code"
|
||||
| "cc-name"
|
||||
| "cc-given-name"
|
||||
| "cc-additional-name"
|
||||
| "cc-family-name"
|
||||
| "cc-number"
|
||||
| "cc-exp"
|
||||
| "cc-exp-month"
|
||||
| "cc-exp-year"
|
||||
| "cc-csc"
|
||||
| "cc-type"
|
||||
| "transaction-currency"
|
||||
| "transaction-amount"
|
||||
| "language"
|
||||
| "bday"
|
||||
| "bday-day"
|
||||
| "bday-month"
|
||||
| "bday-year"
|
||||
| "sex"
|
||||
| "tel"
|
||||
| "tel-country-code"
|
||||
| "tel-national"
|
||||
| "tel-area-code"
|
||||
| "tel-local"
|
||||
| "tel-extension"
|
||||
| "impp"
|
||||
| "url"
|
||||
| "photo";
|
||||
};
|
||||
|
||||
export type Validators = Partial<{
|
||||
|
@ -1,13 +1,12 @@
|
||||
import type { KcContextBase } from "./KcContextBase";
|
||||
import type { KcContextBase, Attribute } from "./KcContextBase";
|
||||
import { kcContextMocks, kcContextCommonMock } from "./kcContextMocks";
|
||||
import { ftlValuesGlobalName } from "../../bin/build-keycloak-theme/ftlValuesGlobalName";
|
||||
import type { AndByDiscriminatingKey } from "../tools/AndByDiscriminatingKey";
|
||||
import type { DeepPartial } from "../tools/DeepPartial";
|
||||
import { deepAssign } from "../tools/deepAssign";
|
||||
|
||||
export type ExtendsKcContextBase<KcContextExtended extends { pageId: string }> = [KcContextExtended] extends [never]
|
||||
? KcContextBase
|
||||
: AndByDiscriminatingKey<"pageId", KcContextExtended & KcContextBase.Common, KcContextBase>;
|
||||
import { id } from "tsafe/id";
|
||||
import { exclude } from "tsafe/exclude";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { ExtendsKcContextBase } from "./getKcContextFromWindow";
|
||||
import { getKcContextFromWindow } from "./getKcContextFromWindow";
|
||||
|
||||
export function getKcContext<KcContextExtended extends { pageId: string } = never>(params?: {
|
||||
mockPageId?: ExtendsKcContextBase<KcContextExtended>["pageId"];
|
||||
@ -44,12 +43,55 @@ export function getKcContext<KcContextExtended extends { pageId: string } = neve
|
||||
"target": kcContext,
|
||||
"source": partialKcContextCustomMock,
|
||||
});
|
||||
|
||||
if (partialKcContextCustomMock.pageId === "register-user-profile.ftl") {
|
||||
assert(kcContextDefaultMock?.pageId === "register-user-profile.ftl");
|
||||
|
||||
const { attributes } = kcContextDefaultMock.profile;
|
||||
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes = [];
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName = {};
|
||||
|
||||
const partialAttributes = [
|
||||
...((partialKcContextCustomMock as DeepPartial<KcContextBase.RegisterUserProfile>).profile?.attributes ?? []),
|
||||
].filter(exclude(undefined));
|
||||
|
||||
attributes.forEach(attribute => {
|
||||
const partialAttribute = partialAttributes.find(({ name }) => name === attribute.name);
|
||||
|
||||
const augmentedAttribute: Attribute = {} as any;
|
||||
|
||||
deepAssign({
|
||||
"target": augmentedAttribute,
|
||||
"source": attribute,
|
||||
});
|
||||
|
||||
if (partialAttribute !== undefined) {
|
||||
partialAttributes.splice(partialAttributes.indexOf(partialAttribute), 1);
|
||||
|
||||
deepAssign({
|
||||
"target": augmentedAttribute,
|
||||
"source": partialAttribute,
|
||||
});
|
||||
}
|
||||
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(augmentedAttribute);
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[augmentedAttribute.name] = augmentedAttribute;
|
||||
});
|
||||
|
||||
partialAttributes.forEach(partialAttribute => {
|
||||
const { name } = partialAttribute;
|
||||
|
||||
assert(name !== undefined, "If you define a mock attribute it must have at least a name");
|
||||
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributes.push(partialAttribute as any);
|
||||
id<KcContextBase.RegisterUserProfile>(kcContext).profile.attributesByName[name] = partialAttribute as any;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
return { kcContext };
|
||||
}
|
||||
|
||||
return {
|
||||
"kcContext": typeof window === "undefined" ? undefined : (window as any)[ftlValuesGlobalName],
|
||||
};
|
||||
return { "kcContext": getKcContextFromWindow<KcContextExtended>() };
|
||||
}
|
||||
|
11
src/lib/getKcContext/getKcContextFromWindow.ts
Normal file
11
src/lib/getKcContext/getKcContextFromWindow.ts
Normal file
@ -0,0 +1,11 @@
|
||||
import type { KcContextBase } from "./KcContextBase";
|
||||
import type { AndByDiscriminatingKey } from "../tools/AndByDiscriminatingKey";
|
||||
import { ftlValuesGlobalName } from "../../bin/build-keycloak-theme/ftlValuesGlobalName";
|
||||
|
||||
export type ExtendsKcContextBase<KcContextExtended extends { pageId: string }> = [KcContextExtended] extends [never]
|
||||
? KcContextBase
|
||||
: AndByDiscriminatingKey<"pageId", KcContextExtended & KcContextBase.Common, KcContextBase>;
|
||||
|
||||
export function getKcContextFromWindow<KcContextExtended extends { pageId: string } = never>(): ExtendsKcContextBase<KcContextExtended> | undefined {
|
||||
return typeof window === "undefined" ? undefined : (window as any)[ftlValuesGlobalName];
|
||||
}
|
@ -1,2 +1,3 @@
|
||||
export type { KcContextBase, Attribute, Validators } from "./KcContextBase";
|
||||
export type { ExtendsKcContextBase } from "./getKcContextFromWindow";
|
||||
export { getKcContext } from "./getKcContext";
|
||||
|
@ -278,29 +278,6 @@ export const kcContextMocks: KcContextBase[] = [
|
||||
"readOnly": false,
|
||||
"name": "lastName",
|
||||
},
|
||||
{
|
||||
"validators": {
|
||||
"length": {
|
||||
"ignore.empty.value": true,
|
||||
"min": "3",
|
||||
"max": "9",
|
||||
},
|
||||
"up-immutable-attribute": {},
|
||||
"up-attribute-required-by-metadata-value": {},
|
||||
"email": {
|
||||
"ignore.empty.value": true,
|
||||
},
|
||||
},
|
||||
"displayName": "${foo}",
|
||||
"annotations": {
|
||||
"this_is_second_key": "this_is_second_value",
|
||||
"this_is_first_key": "this_is_first_value",
|
||||
},
|
||||
"required": true,
|
||||
"groupAnnotations": {},
|
||||
"readOnly": false,
|
||||
"name": "foo",
|
||||
},
|
||||
];
|
||||
|
||||
return {
|
||||
|
@ -1,5 +1,5 @@
|
||||
import { createUseGlobalState } from "powerhooks/useGlobalState";
|
||||
import { getKcContext } from "../getKcContext";
|
||||
import { getKcContextFromWindow } from "../getKcContext/getKcContextFromWindow";
|
||||
import { getBestMatchAmongKcLanguageTag } from "./KcLanguageTag";
|
||||
import type { StatefulEvt } from "powerhooks";
|
||||
import { KcLanguageTag } from "./KcLanguageTag";
|
||||
@ -8,7 +8,7 @@ import { KcLanguageTag } from "./KcLanguageTag";
|
||||
const wrap = createUseGlobalState(
|
||||
"kcLanguageTag",
|
||||
() => {
|
||||
const { kcContext } = getKcContext();
|
||||
const kcContext = getKcContextFromWindow();
|
||||
|
||||
const languageLike = kcContext?.locale?.current ?? (typeof navigator === "undefined" ? undefined : navigator.language);
|
||||
|
||||
|
@ -1,9 +1,12 @@
|
||||
import { assert } from "tsafe/assert";
|
||||
import { is } from "tsafe/is";
|
||||
import { deepClone } from "./deepClone";
|
||||
|
||||
//Warning: Be mindful that because of array this is not idempotent.
|
||||
export function deepAssign(params: { target: Record<string, unknown>; source: Record<string, unknown> }) {
|
||||
const { target, source } = params;
|
||||
const { target } = params;
|
||||
|
||||
const source = deepClone(params.source);
|
||||
|
||||
Object.keys(source).forEach(key => {
|
||||
var dereferencedSource = source[key];
|
||||
|
@ -1,3 +1,17 @@
|
||||
export function deepClone<T>(arg: T): T {
|
||||
return JSON.parse(JSON.stringify(arg));
|
||||
import "minimal-polyfills/Object.fromEntries";
|
||||
|
||||
export function deepClone<T>(o: T): T {
|
||||
if (!(o instanceof Object)) {
|
||||
return o;
|
||||
}
|
||||
|
||||
if (typeof o === "function") {
|
||||
return o;
|
||||
}
|
||||
|
||||
if (o instanceof Array) {
|
||||
return o.map(deepClone) as any;
|
||||
}
|
||||
|
||||
return Object.fromEntries(Object.entries(o).map(([key, value]) => [key, deepClone(value)])) as any;
|
||||
}
|
||||
|
@ -312,6 +312,7 @@ export function useFormValidationSlice(params: {
|
||||
"validators": passwordValidators,
|
||||
"annotations": {},
|
||||
"groupAnnotations": {},
|
||||
"autocomplete": "new-password",
|
||||
}),
|
||||
id<Attribute>({
|
||||
"name": "password-confirm",
|
||||
@ -328,6 +329,7 @@ export function useFormValidationSlice(params: {
|
||||
},
|
||||
"annotations": {},
|
||||
"groupAnnotations": {},
|
||||
"autocomplete": "new-password",
|
||||
}),
|
||||
]),
|
||||
],
|
||||
|
@ -1,6 +1,6 @@
|
||||
import { getKcContext } from "../../lib/getKcContext";
|
||||
import type { KcContextBase } from "../../lib/getKcContext";
|
||||
import type { ExtendsKcContextBase } from "../../lib/getKcContext/getKcContext";
|
||||
import type { ExtendsKcContextBase } from "../../lib/getKcContext";
|
||||
import { same } from "evt/tools/inDepth";
|
||||
import { assert } from "tsafe/assert";
|
||||
import type { Equals } from "tsafe";
|
||||
|
30
yarn.lock
30
yarn.lock
@ -771,11 +771,6 @@ inherits@2, inherits@^2.0.1, inherits@~2.0.1, inherits@~2.0.3:
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c"
|
||||
integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==
|
||||
|
||||
inherits@2.0.3:
|
||||
version "2.0.3"
|
||||
resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de"
|
||||
integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=
|
||||
|
||||
inline-style-parser@0.1.1:
|
||||
version "0.1.1"
|
||||
resolved "https://registry.yarnpkg.com/inline-style-parser/-/inline-style-parser-0.1.1.tgz#ec8a3b429274e9c0a1f1c4ffa9453a7fef72cea1"
|
||||
@ -1174,6 +1169,11 @@ parse5@^6.0.1:
|
||||
resolved "https://registry.yarnpkg.com/parse5/-/parse5-6.0.1.tgz#e1a1c085c569b3dc08321184f19a39cc27f7c30b"
|
||||
integrity sha512-Ofn/CTFzRGTTxwpNEs9PP93gXShHcTq255nzRYSKe8AkVpZY7e1fpmTfOyoIvjP5HG7Z2ZM7VS9PPhQGW2pOpw==
|
||||
|
||||
path-browserify@^1.0.1:
|
||||
version "1.0.1"
|
||||
resolved "https://registry.yarnpkg.com/path-browserify/-/path-browserify-1.0.1.tgz#d98454a9c3753d5790860f16f68867b9e46be1fd"
|
||||
integrity sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==
|
||||
|
||||
path-exists@^4.0.0:
|
||||
version "4.0.0"
|
||||
resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-4.0.0.tgz#513bdbe2d3b95d7762e8c1137efa195c6c61b5b3"
|
||||
@ -1194,14 +1194,6 @@ path-type@^4.0.0:
|
||||
resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b"
|
||||
integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==
|
||||
|
||||
path@^0.12.7:
|
||||
version "0.12.7"
|
||||
resolved "https://registry.yarnpkg.com/path/-/path-0.12.7.tgz#d4dc2a506c4ce2197eb481ebfcd5b36c0140b10f"
|
||||
integrity sha1-1NwqUGxM4hl+tIHr/NWzbAFAsQ8=
|
||||
dependencies:
|
||||
process "^0.11.1"
|
||||
util "^0.10.3"
|
||||
|
||||
picomatch@^2.2.3:
|
||||
version "2.3.0"
|
||||
resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.0.tgz#f1f061de8f6a4bf022892e2d128234fb98302972"
|
||||
@ -1241,11 +1233,6 @@ process-nextick-args@~2.0.0:
|
||||
resolved "https://registry.yarnpkg.com/process-nextick-args/-/process-nextick-args-2.0.1.tgz#7820d9b16120cc55ca9ae7792680ae7dba6d7fe2"
|
||||
integrity sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==
|
||||
|
||||
process@^0.11.1:
|
||||
version "0.11.10"
|
||||
resolved "https://registry.yarnpkg.com/process/-/process-0.11.10.tgz#7332300e840161bda3e69a1d1d91a7d4bc16f182"
|
||||
integrity sha1-czIwDoQBYb2j5podHZGn1LwW8YI=
|
||||
|
||||
prop-types@^15.7.2:
|
||||
version "15.7.2"
|
||||
resolved "https://registry.yarnpkg.com/prop-types/-/prop-types-15.7.2.tgz#52c41e75b8c87e72b9d9360e0206b99dcbffa6c5"
|
||||
@ -1677,13 +1664,6 @@ util-deprecate@~1.0.1:
|
||||
resolved "https://registry.yarnpkg.com/util-deprecate/-/util-deprecate-1.0.2.tgz#450d4dc9fa70de732762fbd2d4a28981419a0ccf"
|
||||
integrity sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=
|
||||
|
||||
util@^0.10.3:
|
||||
version "0.10.4"
|
||||
resolved "https://registry.yarnpkg.com/util/-/util-0.10.4.tgz#3aa0125bfe668a4672de58857d3ace27ecb76901"
|
||||
integrity sha512-0Pm9hTQ3se5ll1XihRic3FDIku70C+iHUdT/W926rSgHV5QgXsYbKZN8MSC3tJtSkhuROzvsQjAaFENRXr+19A==
|
||||
dependencies:
|
||||
inherits "2.0.3"
|
||||
|
||||
vfile-message@^2.0.0:
|
||||
version "2.0.4"
|
||||
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-2.0.4.tgz#5b43b88171d409eae58477d13f23dd41d52c371a"
|
||||
|
Reference in New Issue
Block a user