Répare les liens interne dans la documentation

Les liens dans le markdown ne prenaient pas en compte le `basename`
configuré via react-router/history.

Utilisation de `react-markdown` au lieu de `marked` qui s'inter-opère
mieux avec notre UI.
pull/607/head
Maxime Quandalle 2019-07-09 15:35:09 +02:00
parent 7ea44a7b46
commit db90552f6a
18 changed files with 506 additions and 332 deletions

View File

@ -29,7 +29,6 @@
"i18next": "^14.1.1",
"iframe-resizer": "^3.6.2",
"js-yaml": "^3.13.1",
"marked": "^0.3.17",
"nearley": "^2.16.0",
"ramda": "^0.25.0",
"raven-for-redux": "^1.3.1",
@ -42,6 +41,7 @@
"react-helmet": "6.0.0-beta",
"react-highlight-words": "^0.11.0",
"react-i18next": "^10.0.1",
"react-markdown": "^4.1.0",
"react-number-format": "^4.0.8",
"react-redux": "^7.0.3",
"react-router": "^5.0.1",

View File

@ -1,4 +1,4 @@
import marked from 'Engine/marked'
import { Markdown } from 'Components/utils/markdown'
import { path } from 'ramda'
import React, { Component } from 'react'
import './Dictionary.css'
@ -18,9 +18,6 @@ export let AttachDictionary = dictionary => Decorated =>
if (!term) return null
this.setState({ explanation, term })
}
renderExplanationMarkdown(explanation, term) {
return marked(`### Mécanisme : ${term}\n\n${explanation}`)
}
render() {
let { explanation, term } = this.state
return (
@ -29,11 +26,11 @@ export let AttachDictionary = dictionary => Decorated =>
{explanation && (
<Overlay
onClose={() => this.setState({ term: null, explanation: null })}>
<div
id="dictionaryPanel"
dangerouslySetInnerHTML={{
__html: this.renderExplanationMarkdown(explanation, term)
}}
<div id="dictionaryPanel">
<Markdown
source={`### Mécanisme : ${term}\n\n${explanation}`}
/>
</div>
/>
</Overlay>
)}

View File

@ -1,6 +1,5 @@
import { goToQuestion, hideControl } from 'Actions/actions'
import { makeJsx } from 'Engine/evaluation'
import { createMarkdownDiv } from 'Engine/marked'
import { compose } from 'ramda'
import React from 'react'
import emoji from 'react-easy-emoji'
@ -9,6 +8,7 @@ import { connect } from 'react-redux'
import { analysisWithDefaultsSelector } from 'Selectors/analyseSelectors'
import animate from 'Ui/animate'
import './Controls.css'
import { Markdown } from './utils/markdown'
import withColours from './utils/withColours'
function Controls({
@ -50,7 +50,7 @@ function Controls({
{emoji(level == 'avertissement' ? '⚠️' : '')}
<div className="controlText ui__ card">
{message ? (
createMarkdownDiv(message)
<Markdown source={message} />
) : (
<span id="controlExplanation">{makeJsx(evaluated)}</span>
)}

View File

@ -1,9 +1,9 @@
import { EXPLAIN_VARIABLE } from 'Actions/actions'
import { Markdown } from 'Components/utils/markdown'
import withColours from 'Components/utils/withColours'
import marked from 'Engine/marked'
import { findRuleByDottedName } from 'Engine/rules'
import { compose } from 'ramda'
import React, { Component } from 'react'
import React from 'react'
import { connect } from 'react-redux'
import { flatRulesSelector } from 'Selectors/analyseSelectors'
import References from '../rule/References'
@ -20,43 +20,32 @@ export default compose(
})
),
withColours
)(
class Aide extends Component {
renderExplanationMarkdown(explanation, term) {
return marked(`# ${term} \n\n${explanation}`)
}
render() {
let { flatRules, explained, stopExplaining, colours } = this.props
)(function Aide({ flatRules, explained, stopExplaining, colours }) {
if (!explained) return <section id="helpWrapper" />
if (!explained) return <section id="helpWrapper" />
let rule = findRuleByDottedName(flatRules, explained),
text = rule.description,
refs = rule.références
let rule = findRuleByDottedName(flatRules, explained),
text = rule.description,
refs = rule.références
return (
<div id="helpWrapper" className="active">
<section id="help">
<button
id="closeHelp"
onClick={stopExplaining}
style={{ color: colours.colour }}>
</button>
<p
dangerouslySetInnerHTML={{
__html: this.renderExplanationMarkdown(text, rule.title)
}}
/>
{refs && (
<div>
<p>Pour en savoir plus: </p>
<References refs={refs} />
</div>
)}
</section>
</div>
)
}
}
)
return (
<div id="helpWrapper" className="active">
<section id="help">
<button
id="closeHelp"
onClick={stopExplaining}
style={{ color: colours.colour }}>
</button>
<p>
<Markdown source={`# ${rule.title} \n\n${text}`} />
</p>
{refs && (
<div>
<p>Pour en savoir plus: </p>
<References refs={refs} />
</div>
)}
</section>
</div>
)
})

View File

@ -5,6 +5,7 @@ import React, { Component } from 'react'
import { withTranslation } from 'react-i18next'
import { connect } from 'react-redux'
import { change, Field } from 'redux-form'
import { Markdown } from '../utils/markdown'
/*
This higher order component wraps "Form" components (e.g. Question.js), that represent user inputs,
@ -37,7 +38,7 @@ export var FormDecorator = formType => RenderField =>
render() {
let {
stepAction,
subquestion,
subquestionMarkdown,
valueType,
defaultValue,
fieldName,
@ -61,10 +62,9 @@ export var FormDecorator = formType => RenderField =>
{this.props.question}{' '}
{!inversion && <Explicable dottedName={fieldName} />}
</h3>
<div
className="step-subquestion"
dangerouslySetInnerHTML={{ __html: subquestion }}
/>
<div className="step-subquestion">
<Markdown source={subquestionMarkdown} />
</div>
</div>
</div>

View File

@ -1,11 +1,11 @@
import PeriodSwitch from 'Components/PeriodSwitch'
import withColours from 'Components/utils/withColours'
import { createMarkdownDiv } from 'Engine/marked'
import { path } from 'ramda'
import React from 'react'
import emoji from 'react-easy-emoji'
import { Trans } from 'react-i18next'
import { capitalise0 } from '../../utils'
import { Markdown } from '../utils/markdown'
import Destinataire from './Destinataire'
import './Header.css'
import Namespace from './Namespace'
@ -38,7 +38,7 @@ let RuleHeader = withColours(
</header>
<div id="ruleHeader__content">
<div id="ruleHeader__description">
{createMarkdownDiv(description || question)}
<Markdown source={description || question} />
</div>
{(type || flatRule['période']) && (
<div id="ruleHeader__infobox">

View File

@ -2,8 +2,8 @@ import { T } from 'Components'
import withColours from 'Components/utils/withColours'
import withLanguage from 'Components/utils/withLanguage'
import withSitePaths from 'Components/utils/withSitePaths'
import Value from 'Components/Value'
import knownMecanisms from 'Engine/known-mecanisms.yaml'
import { createMarkdownDiv } from 'Engine/marked'
import {
encodeRuleName,
findRuleByDottedName,
@ -24,12 +24,12 @@ import {
} from 'Selectors/analyseSelectors'
import Animate from 'Ui/animate'
import { AttachDictionary } from '../AttachDictionary'
import { Markdown } from '../utils/markdown'
import Algorithm from './Algorithm'
import Examples from './Examples'
import RuleHeader from './Header'
import References from './References'
import './Rule.css'
import Value from 'Components/Value'
let LazySource = React.lazy(() => import('./RuleSource'))
@ -145,7 +145,7 @@ export default compose(
{flatRule.note && (
<section id="notes">
<h3>Note: </h3>
{createMarkdownDiv(flatRule.note)}
<Markdown source={flatRule.note} />
</section>
)}
<Examples

View File

@ -22,6 +22,14 @@ button {
border-radius: 0;
}
blockquote {
background: var(--lighterColour);
border-radius: 0.6em;
padding: 1.2em 1em 0.4em;
margin: 0.6em;
color: #333;
}
.ui__.answer-group {
display: flex;
align-items: center;
@ -83,5 +91,3 @@ span.ui__.enumeration:not(:last-of-type)::after {
margin: 0 0.3rem;
display: inline-block;
}

View File

@ -0,0 +1,2 @@
import { createContext } from 'react'
export const IsEmbeddedContext = createContext(false)

View File

@ -0,0 +1,29 @@
import React from 'react'
import ReactMarkdown from 'react-markdown'
import { Link } from 'react-router-dom'
function LinkRenderer({ href, children }) {
if (href.startsWith('http')) {
return (
<a target="_blank" href={href}>
{children}
</a>
)
} else {
return <Link to={href}>{children}</Link>
}
}
export const Markdown = ({
source,
className = '',
renderers = {},
otherProps
}) => (
<ReactMarkdown
source={source}
className={`markdown ${className}`}
renderers={{ ...renderers, link: LinkRenderer }}
{...otherProps}
/>
)

View File

@ -1,27 +0,0 @@
import marked from 'marked'
import React from 'react'
let customMarked = new marked.Renderer()
customMarked.link = (href, title, text) =>
`<a target="_blank" href="${href}" title="${title}">${text}</a>`
marked.setOptions({
renderer: customMarked
})
export let createMarkdownDiv = markdown => (
<div
className="markdown"
css={`
blockquote {
background: var(--lighterColour);
border-radius: 0.6em;
padding: 1.2em 1em 0.4em;
margin: 0.6em;
color: #333;
}
`}
dangerouslySetInnerHTML={{ __html: marked(markdown || '') }}
/>
)
export default marked

View File

@ -1,264 +1,263 @@
import { parseUnit } from "Engine/units";
import {
assoc,
chain,
dropLast,
find,
fromPairs,
has,
is,
isNil,
join,
last,
map,
path,
pipe,
propEq,
props,
range,
reduce,
reduced,
reject,
split,
take,
toPairs,
trim,
when
} from 'ramda'
import rawRules from 'Règles/base.yaml'
import translations from 'Règles/externalized.yaml'
assoc,
chain,
dropLast,
find,
fromPairs,
has,
is,
isNil,
join,
last,
map,
path,
pipe,
propEq,
props,
range,
reduce,
reduced,
reject,
split,
take,
toPairs,
trim,
when
} from "ramda";
import rawRules from "Règles/base.yaml";
import translations from "Règles/externalized.yaml";
// TODO - should be in UI, not engine
import { capitalise0, coerceArray } from '../utils'
import marked from './marked'
import possibleVariableTypes from './possibleVariableTypes.yaml'
import { parseUnit } from 'Engine/units'
import { capitalise0, coerceArray } from "../utils";
import possibleVariableTypes from "./possibleVariableTypes.yaml";
/***********************************
Functions working on one rule */
export let enrichRule = rule => {
try {
let unit = rule.unité && parseUnit(rule.unité)
return {
...rule,
type: possibleVariableTypes.find(t => has(t, rule) || rule.type === t),
name: rule['nom'],
title: capitalise0(rule['titre'] || rule['nom']),
ns: rule['espace'],
dottedName: buildDottedName(rule),
subquestion: rule['sous-question'] && marked(rule['sous-question']),
defaultValue: rule['par défaut'],
examples: rule['exemples'],
icons: rule['icônes'],
summary: rule['résumé'],
unit
}
} catch (e) {
console.log(e)
throw new Error('Problem enriching ' + JSON.stringify(rule))
}
}
try {
let unit = rule.unité && parseUnit(rule.unité);
return {
...rule,
type: possibleVariableTypes.find(t => has(t, rule) || rule.type === t),
name: rule["nom"],
title: capitalise0(rule["titre"] || rule["nom"]),
ns: rule["espace"],
dottedName: buildDottedName(rule),
subquestionMarkdown: rule["sous-question"],
defaultValue: rule["par défaut"],
examples: rule["exemples"],
icons: rule["icônes"],
summary: rule["résumé"],
unit
};
} catch (e) {
console.log(e);
throw new Error("Problem enriching " + JSON.stringify(rule));
}
};
export let buildDottedName = rule =>
rule['espace'] ? [rule['espace'], rule['nom']].join(' . ') : rule['nom']
rule["espace"] ? [rule["espace"], rule["nom"]].join(" . ") : rule["nom"];
// les variables dans les tests peuvent être exprimées relativement à l'espace de nom de la règle,
// comme dans sa formule
export let disambiguateExampleSituation = (rules, rule) =>
pipe(
toPairs,
map(([k, v]) => [disambiguateRuleReference(rules, rule, k), v]),
fromPairs
)
pipe(
toPairs,
map(([k, v]) => [disambiguateRuleReference(rules, rule, k), v]),
fromPairs
);
export let hasKnownRuleType = rule => rule && enrichRule(rule).type
export let hasKnownRuleType = rule => rule && enrichRule(rule).type;
export let splitName = split(' . '),
joinName = join(' . ')
export let splitName = split(" . "),
joinName = join(" . ");
export let parentName = pipe(
splitName,
dropLast(1),
joinName
)
splitName,
dropLast(1),
joinName
);
export let nameLeaf = pipe(
splitName,
last
)
splitName,
last
);
export let encodeRuleName = name =>
encodeURI(name.replace(/\s\.\s/g, '/').replace(/\s/g, '-'))
encodeURI(name.replace(/\s\.\s/g, "/").replace(/\s/g, "-"));
export let decodeRuleName = name =>
decodeURI(name.replace(/\//g, ' . ').replace(/-/g, ' '))
decodeURI(name.replace(/\//g, " . ").replace(/-/g, " "));
export let ruleParents = dottedName => {
let fragments = splitName(dottedName) // dottedName ex. [CDD . événements . rupture]
return range(1, fragments.length)
.map(nbEl => take(nbEl)(fragments))
.reverse() // -> [ [CDD . événements . rupture], [CDD . événements], [CDD] ]
}
let fragments = splitName(dottedName); // dottedName ex. [CDD . événements . rupture]
return range(1, fragments.length)
.map(nbEl => take(nbEl)(fragments))
.reverse(); // -> [ [CDD . événements . rupture], [CDD . événements], [CDD] ]
};
/* Les variables peuvent être exprimées dans la formule d'une règle relativement à son propre espace de nom, pour une plus grande lisibilité. Cette fonction résoud cette ambiguité.
*/
export let disambiguateRuleReference = (
allRules,
{ dottedName, name },
partialName
allRules,
{ dottedName, name },
partialName
) => {
let pathPossibilities = [
[], // the top level namespace
...ruleParents(dottedName), // the parents namespace
splitName(dottedName) // the rule's own namespace
],
found = reduce(
(res, path) =>
when(is(Object), reduced)(
do {
let dottedNameToCheck = [...path, partialName].join(' . ')
findRuleByDottedName(allRules, dottedNameToCheck)
}
),
null,
pathPossibilities
)
let pathPossibilities = [
[], // the top level namespace
...ruleParents(dottedName), // the parents namespace
splitName(dottedName) // the rule's own namespace
],
found = reduce(
(res, path) =>
when(is(Object), reduced)(
do {
let dottedNameToCheck = [...path, partialName].join(" . ");
findRuleByDottedName(allRules, dottedNameToCheck);
}
),
null,
pathPossibilities
);
return (
(found && found.dottedName) ||
do {
throw new Error(
`OUUUUPS la référence '${partialName}' dans la règle '${name}' est introuvable dans la base`
)
}
)
}
return (
(found && found.dottedName) ||
do {
throw new Error(
`OUUUUPS la référence '${partialName}' dans la règle '${name}' est introuvable dans la base`
);
}
);
};
export let collectDefaults = pipe(
map(props(['dottedName', 'defaultValue'])),
reject(([, v]) => v === undefined),
fromPairs
)
map(props(["dottedName", "defaultValue"])),
reject(([, v]) => v === undefined),
fromPairs
);
/****************************************
Méthodes de recherche d'une règle */
export let findRuleByName = (allRules, query) =>
(Array.isArray(allRules) ? allRules : Object.values(allRules)).find(
({ name }) => name === query
)
(Array.isArray(allRules) ? allRules : Object.values(allRules)).find(
({ name }) => name === query
);
export let findRulesByName = (allRules, query) =>
(Array.isArray(allRules) ? allRules : Object.values(allRules)).filter(
({ name }) => name === query
)
(Array.isArray(allRules) ? allRules : Object.values(allRules)).filter(
({ name }) => name === query
);
export let findRuleByDottedName = (allRules, dottedName) =>
Array.isArray(allRules)
? allRules.find(rule => rule.dottedName == dottedName)
: allRules[dottedName]
Array.isArray(allRules)
? allRules.find(rule => rule.dottedName == dottedName)
: allRules[dottedName];
export let findRule = (rules, nameOrDottedName) =>
nameOrDottedName.includes(' . ')
? findRuleByDottedName(rules, nameOrDottedName)
: findRuleByName(rules, nameOrDottedName)
nameOrDottedName.includes(" . ")
? findRuleByDottedName(rules, nameOrDottedName)
: findRuleByName(rules, nameOrDottedName);
export let findRuleByNamespace = (allRules, ns) =>
allRules.filter(propEq('ns', ns))
allRules.filter(propEq("ns", ns));
/*********************************
Autres */
export let queryRule = rule => query => path(query.split(' . '))(rule)
export let queryRule = rule => query => path(query.split(" . "))(rule);
// Redux-form stores the form values as a nested object
// This helper makes a dottedName => value Map
export let nestedSituationToPathMap = situation => {
if (situation == undefined) return {}
let rec = (o, currentPath) =>
typeof o === 'object'
? chain(([k, v]) => rec(v, [...currentPath, trim(k)]), toPairs(o))
: [[currentPath.join(' . '), o + '']]
if (situation == undefined) return {};
let rec = (o, currentPath) =>
typeof o === "object"
? chain(([k, v]) => rec(v, [...currentPath, trim(k)]), toPairs(o))
: [[currentPath.join(" . "), o + ""]];
return fromPairs(rec(situation, []))
}
return fromPairs(rec(situation, []));
};
/* Traduction */
export let translateAll = (translations, flatRules) => {
let translationsOf = rule => translations[buildDottedName(rule)],
translateProp = (lang, translation) => (rule, prop) => {
let propTrans = translation[prop + '.' + lang]
if (prop === 'suggestions' && propTrans)
return assoc(
'suggestions',
pipe(
toPairs,
map(([key, translatedKey]) => [
translatedKey,
rule.suggestions[key]
]),
fromPairs
)(propTrans),
rule
)
return propTrans ? assoc(prop, propTrans, rule) : rule
},
translateRule = (lang, translations, props) => rule => {
let ruleTrans = translationsOf(rule)
return ruleTrans
? reduce(translateProp(lang, ruleTrans), rule, props)
: rule
}
let translationsOf = rule => translations[buildDottedName(rule)],
translateProp = (lang, translation) => (rule, prop) => {
let propTrans = translation[prop + "." + lang];
if (prop === "suggestions" && propTrans)
return assoc(
"suggestions",
pipe(
toPairs,
map(([key, translatedKey]) => [
translatedKey,
rule.suggestions[key]
]),
fromPairs
)(propTrans),
rule
);
return propTrans ? assoc(prop, propTrans, rule) : rule;
},
translateRule = (lang, translations, props) => rule => {
let ruleTrans = translationsOf(rule);
return ruleTrans
? reduce(translateProp(lang, ruleTrans), rule, props)
: rule;
};
let targets = [
'titre',
'description',
'question',
'sous-question',
'résumé',
'suggestions',
'contrôles'
]
let targets = [
"titre",
"description",
"question",
"sous-question",
"résumé",
"suggestions",
"contrôles"
];
return map(translateRule('en', translations, targets), flatRules)
}
return map(translateRule("en", translations, targets), flatRules);
};
// On enrichit la base de règles avec des propriétés dérivées de celles du YAML
export let rules = translateAll(translations, rawRules).map(rule =>
enrichRule(rule)
)
enrichRule(rule)
);
export let rulesFr = rawRules.map(rule => enrichRule(rule))
export let rulesFr = rawRules.map(rule => enrichRule(rule));
export let findParentDependency = (rules, rule) => {
// A parent dependency means that one of a rule's parents is not just a namespace holder, it is a boolean question. E.g. is it a fixed-term contract, yes / no
// When it is resolved to false, then the whole branch under it is disactivated (non applicable)
// It lets those children omit obvious and repetitive parent applicability tests
let parentDependencies = ruleParents(rule.dottedName).map(joinName)
return pipe(
map(parent => findRuleByDottedName(rules, parent)),
reject(isNil),
find(
//Find the first "calculable" parent
({ question, unit, formule }) => question && !unit && !formule //implicitly, the format is boolean
)
)(parentDependencies)
}
// A parent dependency means that one of a rule's parents is not just a namespace holder, it is a boolean question. E.g. is it a fixed-term contract, yes / no
// When it is resolved to false, then the whole branch under it is disactivated (non applicable)
// It lets those children omit obvious and repetitive parent applicability tests
let parentDependencies = ruleParents(rule.dottedName).map(joinName);
return pipe(
map(parent => findRuleByDottedName(rules, parent)),
reject(isNil),
find(
//Find the first "calculable" parent
({ question, unit, formule }) => question && !unit && !formule //implicitly, the format is boolean
)
)(parentDependencies);
};
export let getRuleFromAnalysis = analysis => dottedName => {
if (!analysis) {
throw new Error("[getRuleFromAnalysis] The analysis can't be nil !")
}
let rule = coerceArray(analysis) // In some simulations, there are multiple "branches" : the analysis is run with e.g. 3 different input situations
.map(
analysis =>
analysis.cache[dottedName]?.explanation || // the cache stores a reference to a variable, the variable is contained in the 'explanation' attribute
analysis.targets.find(propEq('dottedName', dottedName))
)
.filter(Boolean)[0]
if (!analysis) {
throw new Error("[getRuleFromAnalysis] The analysis can't be nil !");
}
let rule = coerceArray(analysis) // In some simulations, there are multiple "branches" : the analysis is run with e.g. 3 different input situations
.map(
analysis =>
analysis.cache[dottedName]?.explanation || // the cache stores a reference to a variable, the variable is contained in the 'explanation' attribute
analysis.targets.find(propEq("dottedName", dottedName))
)
.filter(Boolean)[0];
if (!rule) {
throw new Error(
`[getRuleFromAnalysis] Unable to find the rule ${dottedName}`
)
}
if (!rule) {
throw new Error(
`[getRuleFromAnalysis] Unable to find the rule ${dottedName}`
);
}
return rule
}
return rule;
};

View File

@ -1,3 +1,4 @@
import { IsEmbeddedContext } from 'Components/utils/embeddedContext'
import React from 'react'
import { Route } from 'react-router'
import IframeFooter from './IframeFooter'
@ -5,12 +6,14 @@ import SimulateurEmbauche from './SimulateurEmbauche'
export default function Iframes() {
return (
<div className="ui__ container">
<Route
path="/iframes/simulateur-embauche"
component={SimulateurEmbauche}
/>
<IframeFooter />
</div>
<IsEmbeddedContext.Provider value={true}>
<div className="ui__ container">
<Route
path="/iframes/simulateur-embauche"
component={SimulateurEmbauche}
/>
<IframeFooter />
</div>
</IsEmbeddedContext.Provider>
)
}

View File

@ -5,9 +5,10 @@ import SalaryExplanation from 'Components/SalaryExplanation'
import Simulation from 'Components/Simulation'
import salariéConfig from 'Components/simulationConfigs/salarié.yaml'
import withSimulationConfig from 'Components/simulationConfigs/withSimulationConfig'
import { IsEmbeddedContext } from 'Components/utils/embeddedContext'
import { Markdown } from 'Components/utils/markdown'
import withLanguage from 'Components/utils/withLanguage'
import withSitePaths from 'Components/utils/withSitePaths'
import { createMarkdownDiv } from 'Engine/marked'
import { compose } from 'ramda'
import emoji from 'react-easy-emoji'
import { Helmet } from 'react-helmet'
@ -18,6 +19,7 @@ export default compose(
withTranslation(),
withLanguage
)(function Salarié({ t, language }) {
const isEmbedded = React.useContext(IsEmbeddedContext)
return (
<>
<Helmet>
@ -49,18 +51,19 @@ export default compose(
</Banner>
)}
<SalarySimulation />
<SalariéExplications />
{!isEmbedded && <SalariéExplications />}
</>
)
})
const SalariéExplications = withSitePaths(({ sitePaths }) =>
createMarkdownDiv(`
const SalariéExplications = withSitePaths(({ sitePaths }) => (
<Markdown
source={`
## Calculer son salaire net
Lors de l'entretien d'embauche l'employeur propose en général une rémunération exprimée en « brut ». Le montant annoncé inclut ainsi les cotisations salariales, qui servent à financer la protection sociale du salarié (retraite, maladie, famille, etc.) et qui sont retranchées du salaire « net » perçu par le salarié.
Vous pouvez utiliser notre simulateur pour convertir le **salaire brut en net** : il vous suffit pour cela de saisir la rémunération annoncée dans la case salaire brut. La simulation peut-être affinée en répondant aux différentes questions (sur le CDD, statut cadre, etc.).
Vous pouvez utiliser notre simulateur pour convertir le **salaire brut en net** : il vous suffit pour cela saisir la rémunération annoncée dans la case salaire brut. La simulation peut-être affinée en répondant aux différentes questions (sur le CDD, statut cadre, etc.).
Par ailleurs depuis 2019, l'[impôt sur le revenu](/documentation/impôt/impôt-sur-le-revenu) est prélevé à la source. Pour ce faire, la direction générale des finances publiques (DGFiP) transmet à l'employeur le taux d'imposition calculé à partir de la déclaration de revenu du salarié. Si ce taux est inconnu, par exemple lors d'une première année d'activité, l'employeur utilise le [taux neutre](/documentation/impôt/neutre). C'est aussi le taux neutre que nous utilisons dans le simulateur pour calculer le « net après impôt » qui est versé sur le compte bancaire du salarié.
@ -73,8 +76,9 @@ Si vous cherchez à embaucher, vous pouvez calculer le coût total de la rémun
En plus du salaire, notre simulateur prend en compte le calcul des avantages en nature (téléphone, véhicule de fonction, etc.), ainsi que la mutuelle santé obligatoire.
Il existe des [aides différées](/documentation/aides-employeur) à l'embauche qui ne sont pas prises en compte par notre simulateur, vous pouvez les retrouver sur [le portail officiel](http://www.aides-entreprises.fr).
`)
)
`}
/>
))
export let SalarySimulation = compose(
withSimulationConfig(salariéConfig),

View File

@ -1,6 +1,6 @@
import { Markdown } from 'Components/utils/markdown'
import { ScrollToTop } from 'Components/utils/Scroll'
import withSitePaths from 'Components/utils/withSitePaths'
import { createMarkdownDiv } from 'Engine/marked'
import { all } from 'ramda'
import React, { useContext } from 'react'
import emoji from 'react-easy-emoji'
@ -68,7 +68,7 @@ export default withSitePaths(function LocationMeublée({
<h1>
{emoji(data.icônes)} {data.titre}
</h1>
{createMarkdownDiv(data.explication)}
<Markdown source={data.explication} />
{data.plateformes && (
<p>
{emoji('📱 ')}

View File

@ -1,7 +1,7 @@
import React from 'react'
import { createMarkdownDiv } from 'Engine/marked'
import { CheckItem } from 'Ui/Checklist'
import { Markdown } from 'Components/utils/markdown'
import { update } from 'ramda'
import React from 'react'
import { CheckItem } from 'Ui/Checklist'
export default ({ exonérations, dispatch, answers, title }) => {
if (!exonérations) return null
@ -17,7 +17,7 @@ export default ({ exonérations, dispatch, answers, title }) => {
<CheckItem
name={titre}
title={titre}
explanations={createMarkdownDiv(explication)}
explanations={<Markdown source={explication} />}
onChange={checked => {
let action = {
type: 'UPDATE_ACTIVITY',

View File

@ -1,12 +1,12 @@
import { map } from 'ramda'
import { expect } from 'chai'
import { map } from 'ramda'
import {
rules,
disambiguateRuleReference,
ruleParents,
enrichRule,
translateAll,
nestedSituationToPathMap
nestedSituationToPathMap,
ruleParents,
rules,
translateAll
} from '../source/engine/rules'
describe('enrichRule', function() {
@ -23,14 +23,6 @@ describe('enrichRule', function() {
'contrat salarié . CDD'
)
})
it('should render Markdown in sub-questions', function() {
let rule = { nom: 'quoi', 'sous-question': '**wut**' }
expect(enrichRule(rule)).to.have.property(
'subquestion',
'<p><strong>wut</strong></p>\n'
)
})
})
describe('rule checks', function() {

204
yarn.lock
View File

@ -1754,6 +1754,11 @@ babylon@^6.18.0:
resolved "https://registry.yarnpkg.com/babylon/-/babylon-6.18.0.tgz#af2f3b88fa6f5c1e4c634d1a0f8eac4f55b395e3"
integrity sha512-q/UEjfGJ2Cm3oKV71DJz9d25TPnq5rhBVL2Q4fA5wcC3jcrdn7+SssEybFIxwAvvP+YCsCYNKughoF33GxgycQ==
bail@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/bail/-/bail-1.0.4.tgz#7181b66d508aa3055d3f6c13f0a0c720641dde9b"
integrity sha512-S8vuDB4w6YpRhICUDET3guPlQpaJl7od94tpZ0Fvnyp+MKW/HyDTcRDck+29C9g+d/qQHnddRH3+94kZdrW0Ww==
balanced-match@^0.4.2:
version "0.4.2"
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-0.4.2.tgz#cb3f3e3c732dc0f01ee70b403f302e61d7709838"
@ -2458,6 +2463,11 @@ code-point-at@^1.0.0:
resolved "https://registry.yarnpkg.com/code-point-at/-/code-point-at-1.1.0.tgz#0d070b4d043a5bea33a2f1a40e2edb3d9a4ccf77"
integrity sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=
collapse-white-space@^1.0.2:
version "1.0.5"
resolved "https://registry.yarnpkg.com/collapse-white-space/-/collapse-white-space-1.0.5.tgz#c2495b699ab1ed380d29a1091e01063e75dbbe3a"
integrity sha512-703bOOmytCYAX9cXYqoikYIx6twmFCXsnzRQheBcTG3nzKYBR4P/+wkYeH+Mvj7qUz8zZDtdyzbxfnEi/kYzRQ==
collection-visit@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/collection-visit/-/collection-visit-1.0.0.tgz#4bc0373c164bc3291b4d368c829cf1a80a59dca0"
@ -3247,7 +3257,7 @@ domexception@^1.0.1:
dependencies:
webidl-conversions "^4.0.2"
domhandler@^2.3.0:
domhandler@^2.3.0, domhandler@^2.4.2:
version "2.4.2"
resolved "https://registry.yarnpkg.com/domhandler/-/domhandler-2.4.2.tgz#8805097e933d65e85546f726d60f5eb88b44f803"
integrity sha512-JiK04h0Ht5u/80fdLMCEmV4zkNh2BcoMFBmZ/91WtYZ8qVXSKjiw7fXMgFPnHcSZgOo3XdinHvmnDUeMf5R4wA==
@ -3822,7 +3832,7 @@ extend-shallow@^3.0.0, extend-shallow@^3.0.2:
assign-symbols "^1.0.0"
is-extendable "^1.0.1"
extend@~3.0.2:
extend@^3.0.0, extend@~3.0.2:
version "3.0.2"
resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa"
integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==
@ -4708,6 +4718,17 @@ html-parse-stringify2@2.0.1:
dependencies:
void-elements "^2.0.1"
html-to-react@^1.3.4:
version "1.3.4"
resolved "https://registry.yarnpkg.com/html-to-react/-/html-to-react-1.3.4.tgz#647b3a54fdec73a6461864b129fb0d1eec7d4589"
integrity sha512-/tWDdb/8Koi/QEP5YUY1653PcDpBnnMblXRhotnTuhFDjI1Fc6Wzox5d4sw73Xk5rM2OdM5np4AYjT/US/Wj7Q==
dependencies:
domhandler "^2.4.2"
escape-string-regexp "^1.0.5"
htmlparser2 "^3.10.0"
lodash.camelcase "^4.3.0"
ramda "^0.26"
html-webpack-plugin@^3.2.0:
version "3.2.0"
resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-3.2.0.tgz#b01abbd723acaaa7b37b6af4492ebda03d9dd37b"
@ -4721,7 +4742,7 @@ html-webpack-plugin@^3.2.0:
toposort "^1.0.0"
util.promisify "1.0.0"
htmlparser2@^3.3.0, htmlparser2@^3.9.1:
htmlparser2@^3.10.0, htmlparser2@^3.3.0, htmlparser2@^3.9.1:
version "3.10.1"
resolved "https://registry.yarnpkg.com/htmlparser2/-/htmlparser2-3.10.1.tgz#bd679dc3f59897b6a34bb10749c855bb53a9392f"
integrity sha512-IgieNijUMbkDovyoKObU1DUhm1iwNYE/fuifEoEHfd1oZKZDaONBSkal7Y01shxsM49R4XaMdGez3WnF9UfiCQ==
@ -5066,7 +5087,7 @@ is-boolean-object@^1.0.0:
resolved "https://registry.yarnpkg.com/is-boolean-object/-/is-boolean-object-1.0.0.tgz#98f8b28030684219a95f375cfbd88ce3405dff93"
integrity sha1-mPiygDBoQhmpXzdc+9iM40Bd/5M=
is-buffer@^1.1.5, is-buffer@~1.1.1:
is-buffer@^1.1.4, is-buffer@^1.1.5, is-buffer@~1.1.1:
version "1.1.6"
resolved "https://registry.yarnpkg.com/is-buffer/-/is-buffer-1.1.6.tgz#efaa2ea9daa0d7ab2ea13a97b2b8ad51fefbe8be"
integrity sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==
@ -5222,7 +5243,7 @@ is-path-inside@^1.0.0:
dependencies:
path-is-inside "^1.0.1"
is-plain-obj@^1.0.0:
is-plain-obj@^1.0.0, is-plain-obj@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-plain-obj/-/is-plain-obj-1.1.0.tgz#71a50c8429dfca773c92a390a4a03b39fcd51d3e"
integrity sha1-caUMhCnfync8kqOQpKA7OfzVHT4=
@ -5295,11 +5316,21 @@ is-what@^3.2.3:
resolved "https://registry.yarnpkg.com/is-what/-/is-what-3.2.3.tgz#50f76f1bd8e56967e15765d1d34302513701997b"
integrity sha512-c4syLgFnjXTH5qd82Fp/qtUIeM0wA69xbI0KH1QpurMIvDaZFrS8UtAa4U52Dc2qSznaMxHit0gErMp6A/Qk1w==
is-whitespace-character@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-whitespace-character/-/is-whitespace-character-1.0.3.tgz#b3ad9546d916d7d3ffa78204bca0c26b56257fac"
integrity sha512-SNPgMLz9JzPccD3nPctcj8sZlX9DAMJSKH8bP7Z6bohCwuNgX8xbWr1eTAYXX9Vpi/aSn8Y1akL9WgM3t43YNQ==
is-windows@^1.0.1, is-windows@^1.0.2:
version "1.0.2"
resolved "https://registry.yarnpkg.com/is-windows/-/is-windows-1.0.2.tgz#d1850eb9791ecd18e6182ce12a30f396634bb19d"
integrity sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==
is-word-character@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/is-word-character/-/is-word-character-1.0.3.tgz#264d15541cbad0ba833d3992c34e6b40873b08aa"
integrity sha512-0wfcrFgOOOBdgRNT9H33xe6Zi6yhX/uoc4U8NBZGeQQB0ctU1dnlNTyL9JM2646bHDTpsDm1Brb3VPoCIMrd/A==
is-wsl@^1.1.0:
version "1.1.0"
resolved "https://registry.yarnpkg.com/is-wsl/-/is-wsl-1.1.0.tgz#1f16e4aa22b04d1336b66188a66af3c600c3a66d"
@ -5929,10 +5960,10 @@ map-visit@^1.0.0:
dependencies:
object-visit "^1.0.0"
marked@^0.3.17:
version "0.3.19"
resolved "https://registry.yarnpkg.com/marked/-/marked-0.3.19.tgz#5d47f709c4c9fc3c216b6d46127280f40b39d790"
integrity sha512-ea2eGWOqNxPcXv8dyERdSr/6FmzvWwzjMxpfGB/sbMccXoct+xY+YukPD+QTUZwyvK7BZwcr4m21WBOW41pAkg==
markdown-escapes@^1.0.0:
version "1.0.3"
resolved "https://registry.yarnpkg.com/markdown-escapes/-/markdown-escapes-1.0.3.tgz#6155e10416efaafab665d466ce598216375195f5"
integrity sha512-XUi5HJhhV5R74k8/0H2oCbCiYf/u4cO/rX8tnGkRvrqhsr5BRNU6Mg0yt/8UIx1iIS8220BNJsDb7XnILhLepw==
material-colors@^1.2.1:
version "1.2.6"
@ -5962,6 +5993,13 @@ md5@^2.2.1:
crypt "~0.0.1"
is-buffer "~1.1.1"
mdast-add-list-metadata@1.0.1:
version "1.0.1"
resolved "https://registry.yarnpkg.com/mdast-add-list-metadata/-/mdast-add-list-metadata-1.0.1.tgz#95e73640ce2fc1fa2dcb7ec443d09e2bfe7db4cf"
integrity sha512-fB/VP4MJ0LaRsog7hGPxgOrSL3gE/2uEdZyDuSEnKCv/8IkYHiDkIQSbChiJoHyxZZXZ9bzckyRk+vNxFzh8rA==
dependencies:
unist-util-visit-parents "1.1.2"
media-typer@0.3.0:
version "0.3.0"
resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748"
@ -6882,7 +6920,7 @@ parse-asn1@^5.0.0:
pbkdf2 "^3.0.3"
safe-buffer "^5.1.1"
parse-entities@^1.1.2:
parse-entities@^1.1.0, parse-entities@^1.1.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/parse-entities/-/parse-entities-1.2.2.tgz#c31bf0f653b6661354f8973559cb86dd1d5edf50"
integrity sha512-NzfpbxW/NPrzZ/yYSoQxyqUZMZXIdCfE0OIN4ESsnptHJECoUk3FZktxNuzQf4tjt5UEopnxpYJbvYuxIFDdsg==
@ -7652,7 +7690,7 @@ ramda@0.24.1:
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.24.1.tgz#c3b7755197f35b8dc3502228262c4c91ddb6b857"
integrity sha1-w7d1UZfzW43DUCIoJixMkd22uFc=
ramda@0.x, ramda@>=0.15.0:
ramda@0.x, ramda@>=0.15.0, ramda@^0.26:
version "0.26.1"
resolved "https://registry.yarnpkg.com/ramda/-/ramda-0.26.1.tgz#8d41351eb8111c55353617fc3bbffad8e4d35d06"
integrity sha512-hLWjpy7EnsDBb0p+Z3B7rPi3GDeRG5ZtiI33kJhTt+ORCd38AbAIjB/9zRIUoeTbE/AVX5ZkU7m6bznsvrf8eQ==
@ -7830,6 +7868,19 @@ react-lifecycles-compat@^3.0.4:
resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362"
integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA==
react-markdown@^4.1.0:
version "4.1.0"
resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-4.1.0.tgz#7fdf840ecbabc803f28156f7411c726b58f25a73"
integrity sha512-EOHsEAN+aoP8UVz7vTHx6Z63GJfhrO9KItKlfsiBtVVS9tmSWtUaBTw73+2SObrWiOiE2Cs9qUBL7ORsvVhOrA==
dependencies:
html-to-react "^1.3.4"
mdast-add-list-metadata "1.0.1"
prop-types "^15.7.2"
remark-parse "^5.0.0"
unified "^6.1.5"
unist-util-visit "^1.3.0"
xtend "^4.0.1"
react-number-format@^4.0.8:
version "4.0.8"
resolved "https://registry.yarnpkg.com/react-number-format/-/react-number-format-4.0.8.tgz#f0a0dfbeded9a746f4d8b309926cf55d7effebb2"
@ -8217,6 +8268,27 @@ relateurl@0.2.x:
resolved "https://registry.yarnpkg.com/relateurl/-/relateurl-0.2.7.tgz#54dbf377e51440aca90a4cd274600d3ff2d888a9"
integrity sha1-VNvzd+UUQKypCkzSdGANP/LYiKk=
remark-parse@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/remark-parse/-/remark-parse-5.0.0.tgz#4c077f9e499044d1d5c13f80d7a98cf7b9285d95"
integrity sha512-b3iXszZLH1TLoyUzrATcTQUZrwNl1rE70rVdSruJFlDaJ9z5aMkhrG43Pp68OgfHndL/ADz6V69Zow8cTQu+JA==
dependencies:
collapse-white-space "^1.0.2"
is-alphabetical "^1.0.0"
is-decimal "^1.0.0"
is-whitespace-character "^1.0.0"
is-word-character "^1.0.0"
markdown-escapes "^1.0.0"
parse-entities "^1.1.0"
repeat-string "^1.5.4"
state-toggle "^1.0.0"
trim "0.0.1"
trim-trailing-lines "^1.0.0"
unherit "^1.0.4"
unist-util-remove-position "^1.0.0"
vfile-location "^2.0.0"
xtend "^4.0.1"
remove-trailing-separator@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz#c24bce2a283adad5bc3f58e0d48249b92379d8ef"
@ -8238,7 +8310,7 @@ repeat-element@^1.1.2:
resolved "https://registry.yarnpkg.com/repeat-element/-/repeat-element-1.1.3.tgz#782e0d825c0c5a3bb39731f84efee6b742e6b1ce"
integrity sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==
repeat-string@^1.6.1:
repeat-string@^1.5.4, repeat-string@^1.6.1:
version "1.6.1"
resolved "https://registry.yarnpkg.com/repeat-string/-/repeat-string-1.6.1.tgz#8dcae470e1c88abc2d600fff4a776286da75e637"
integrity sha1-jcrkcOHIirwtYA//Sndihtp15jc=
@ -8250,6 +8322,11 @@ repeating@^2.0.0:
dependencies:
is-finite "^1.0.0"
replace-ext@1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/replace-ext/-/replace-ext-1.0.0.tgz#de63128373fcbf7c3ccfa4de5a480c45a67958eb"
integrity sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=
request-progress@0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/request-progress/-/request-progress-0.4.0.tgz#c1954e39086aa85269c5660bcee0142a6a70d7e7"
@ -8850,6 +8927,11 @@ ssri@^6.0.1:
dependencies:
figgy-pudding "^3.5.1"
state-toggle@^1.0.0:
version "1.0.2"
resolved "https://registry.yarnpkg.com/state-toggle/-/state-toggle-1.0.2.tgz#75e93a61944116b4959d665c8db2d243631d6ddc"
integrity sha512-8LpelPGR0qQM4PnfLiplOQNJcIN1/r2Gy0xKB2zKnIW2YzPMt2sR4I/+gtPjhN7Svh9kw+zqEg2SFwpBO9iNiw==
static-extend@^0.1.1:
version "0.1.2"
resolved "https://registry.yarnpkg.com/static-extend/-/static-extend-0.1.2.tgz#60809c39cbff55337226fd5e0b520f341f1fb5c6"
@ -9338,6 +9420,21 @@ trim-right@^1.0.1:
resolved "https://registry.yarnpkg.com/trim-right/-/trim-right-1.0.1.tgz#cb2e1203067e0c8de1f614094b9fe45704ea6003"
integrity sha1-yy4SAwZ+DI3h9hQJS5/kVwTqYAM=
trim-trailing-lines@^1.0.0:
version "1.1.2"
resolved "https://registry.yarnpkg.com/trim-trailing-lines/-/trim-trailing-lines-1.1.2.tgz#d2f1e153161152e9f02fabc670fb40bec2ea2e3a"
integrity sha512-MUjYItdrqqj2zpcHFTkMa9WAv4JHTI6gnRQGPFLrt5L9a6tRMiDnIqYl8JBvu2d2Tc3lWJKQwlGCp0K8AvCM+Q==
trim@0.0.1:
version "0.0.1"
resolved "https://registry.yarnpkg.com/trim/-/trim-0.0.1.tgz#5858547f6b290757ee95cccc666fb50084c460dd"
integrity sha1-WFhUf2spB1fulczMZm+1AITEYN0=
trough@^1.0.0:
version "1.0.4"
resolved "https://registry.yarnpkg.com/trough/-/trough-1.0.4.tgz#3b52b1f13924f460c3fbfd0df69b587dbcbc762e"
integrity sha512-tdzBRDGWcI1OpPVmChbdSKhvSVurznZ8X36AYURAcl+0o2ldlCY2XPzyXNNxwJwwyIU+rIglTCG4kxtNKBQH7Q==
tslib@^1.9.0:
version "1.10.0"
resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a"
@ -9393,6 +9490,14 @@ uglify-js@3.4.x:
commander "~2.19.0"
source-map "~0.6.1"
unherit@^1.0.4:
version "1.1.2"
resolved "https://registry.yarnpkg.com/unherit/-/unherit-1.1.2.tgz#14f1f397253ee4ec95cec167762e77df83678449"
integrity sha512-W3tMnpaMG7ZY6xe/moK04U9fBhi6wEiCYHUW5Mop/wQHf12+79EQGwxYejNdhEz2mkqkBlGwm7pxmgBKMVUj0w==
dependencies:
inherits "^2.0.1"
xtend "^4.0.1"
unicode-canonical-property-names-ecmascript@^1.0.4:
version "1.0.4"
resolved "https://registry.yarnpkg.com/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-1.0.4.tgz#2619800c4c825800efdd8343af7dd9933cbe2818"
@ -9416,6 +9521,18 @@ unicode-property-aliases-ecmascript@^1.0.4:
resolved "https://registry.yarnpkg.com/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-1.0.5.tgz#a9cc6cc7ce63a0a3023fc99e341b94431d405a57"
integrity sha512-L5RAqCfXqAwR3RriF8pM0lU0w4Ryf/GgzONwi6KnL1taJQa7x1TCxdJnILX59WIGOwR57IVxn7Nej0fz1Ny6fw==
unified@^6.1.5:
version "6.2.0"
resolved "https://registry.yarnpkg.com/unified/-/unified-6.2.0.tgz#7fbd630f719126d67d40c644b7e3f617035f6dba"
integrity sha512-1k+KPhlVtqmG99RaTbAv/usu85fcSRu3wY8X+vnsEhIxNP5VbVIDiXnLqyKIG+UMdyTg0ZX9EI6k2AfjJkHPtA==
dependencies:
bail "^1.0.0"
extend "^3.0.0"
is-plain-obj "^1.1.0"
trough "^1.0.0"
vfile "^2.0.0"
x-is-string "^0.1.0"
union-value@^1.0.0:
version "1.0.1"
resolved "https://registry.yarnpkg.com/union-value/-/union-value-1.0.1.tgz#0b6fe7b835aecda61c6ea4d4f02c14221e109847"
@ -9457,6 +9574,42 @@ unique-slug@^2.0.0:
dependencies:
imurmurhash "^0.1.4"
unist-util-is@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/unist-util-is/-/unist-util-is-3.0.0.tgz#d9e84381c2468e82629e4a5be9d7d05a2dd324cd"
integrity sha512-sVZZX3+kspVNmLWBPAB6r+7D9ZgAFPNWm66f7YNb420RlQSbn+n8rG8dGZSkrER7ZIXGQYNm5pqC3v3HopH24A==
unist-util-remove-position@^1.0.0:
version "1.1.3"
resolved "https://registry.yarnpkg.com/unist-util-remove-position/-/unist-util-remove-position-1.1.3.tgz#d91aa8b89b30cb38bad2924da11072faa64fd972"
integrity sha512-CtszTlOjP2sBGYc2zcKA/CvNdTdEs3ozbiJ63IPBxh8iZg42SCCb8m04f8z2+V1aSk5a7BxbZKEdoDjadmBkWA==
dependencies:
unist-util-visit "^1.1.0"
unist-util-stringify-position@^1.0.0, unist-util-stringify-position@^1.1.1:
version "1.1.2"
resolved "https://registry.yarnpkg.com/unist-util-stringify-position/-/unist-util-stringify-position-1.1.2.tgz#3f37fcf351279dcbca7480ab5889bb8a832ee1c6"
integrity sha512-pNCVrk64LZv1kElr0N1wPiHEUoXNVFERp+mlTg/s9R5Lwg87f9bM/3sQB99w+N9D/qnM9ar3+AKDBwo/gm/iQQ==
unist-util-visit-parents@1.1.2:
version "1.1.2"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-1.1.2.tgz#f6e3afee8bdbf961c0e6f028ea3c0480028c3d06"
integrity sha512-yvo+MMLjEwdc3RhhPYSximset7rwjMrdt9E41Smmvg25UQIenzrN83cRnF1JMzoMi9zZOQeYXHSDf7p+IQkW3Q==
unist-util-visit-parents@^2.0.0:
version "2.1.2"
resolved "https://registry.yarnpkg.com/unist-util-visit-parents/-/unist-util-visit-parents-2.1.2.tgz#25e43e55312166f3348cae6743588781d112c1e9"
integrity sha512-DyN5vD4NE3aSeB+PXYNKxzGsfocxp6asDc2XXE3b0ekO2BaRUpBicbbUygfSvYfUz1IkmjFR1YF7dPklraMZ2g==
dependencies:
unist-util-is "^3.0.0"
unist-util-visit@^1.1.0, unist-util-visit@^1.3.0:
version "1.4.1"
resolved "https://registry.yarnpkg.com/unist-util-visit/-/unist-util-visit-1.4.1.tgz#4724aaa8486e6ee6e26d7ff3c8685960d560b1e3"
integrity sha512-AvGNk7Bb//EmJZyhtRUnNMEpId/AZ5Ph/KUpTI09WHQuDZHKovQ1oEv3mfmKpWKtoMzyMC4GLBm1Zy5k12fjIw==
dependencies:
unist-util-visit-parents "^2.0.0"
universal-user-agent@^2.0.0:
version "2.1.0"
resolved "https://registry.yarnpkg.com/universal-user-agent/-/universal-user-agent-2.1.0.tgz#5abfbcc036a1ba490cb941f8fd68c46d3669e8e4"
@ -9642,6 +9795,28 @@ verror@1.10.0:
core-util-is "1.0.2"
extsprintf "^1.2.0"
vfile-location@^2.0.0:
version "2.0.5"
resolved "https://registry.yarnpkg.com/vfile-location/-/vfile-location-2.0.5.tgz#c83eb02f8040228a8d2b3f10e485be3e3433e0a2"
integrity sha512-Pa1ey0OzYBkLPxPZI3d9E+S4BmvfVwNAAXrrqGbwTVXWaX2p9kM1zZ+n35UtVM06shmWKH4RPRN8KI80qE3wNQ==
vfile-message@^1.0.0:
version "1.1.1"
resolved "https://registry.yarnpkg.com/vfile-message/-/vfile-message-1.1.1.tgz#5833ae078a1dfa2d96e9647886cd32993ab313e1"
integrity sha512-1WmsopSGhWt5laNir+633LszXvZ+Z/lxveBf6yhGsqnQIhlhzooZae7zV6YVM1Sdkw68dtAW3ow0pOdPANugvA==
dependencies:
unist-util-stringify-position "^1.1.1"
vfile@^2.0.0:
version "2.3.0"
resolved "https://registry.yarnpkg.com/vfile/-/vfile-2.3.0.tgz#e62d8e72b20e83c324bc6c67278ee272488bf84a"
integrity sha512-ASt4mBUHcTpMKD/l5Q+WJXNtshlWxOogYyGYYrg4lt/vuRjC1EFQtlAofL5VmtVNIZJzWYFJjzGWZ0Gw8pzW1w==
dependencies:
is-buffer "^1.1.4"
replace-ext "1.0.0"
unist-util-stringify-position "^1.0.0"
vfile-message "^1.0.0"
vm-browserify@^1.0.1:
version "1.1.0"
resolved "https://registry.yarnpkg.com/vm-browserify/-/vm-browserify-1.1.0.tgz#bd76d6a23323e2ca8ffa12028dc04559c75f9019"
@ -10007,6 +10182,11 @@ ws@^6.1.0:
dependencies:
async-limiter "~1.0.0"
x-is-string@^0.1.0:
version "0.1.0"
resolved "https://registry.yarnpkg.com/x-is-string/-/x-is-string-0.1.0.tgz#474b50865af3a49a9c4657f05acd145458f77d82"
integrity sha1-R0tQhlrzpJqcRlfwWs0UVFj3fYI=
xml-name-validator@^3.0.0:
version "3.0.0"
resolved "https://registry.yarnpkg.com/xml-name-validator/-/xml-name-validator-3.0.0.tgz#6ae73e06de4d8c6e47f9fb181f78d648ad457c6a"