COMMANDS_TO_RUN+=('./scripts/circleci/build.sh') COMMANDS_TO_RUN+=('yarn test-build --runInBand') COMMANDS_TO_RUN+=('yarn test-build-prod --runInBand') <ins> COMMANDS_TO_RUN+=('./scripts/circleci/upload_build.sh') </ins> fi if [ $((3 % CIRCLE_NODE_TOTAL)) -eq "$CIRCLE_NODE_INDEX" ]; then


} } while (nextEffect !== null) { <ins> if (__DEV__) { setCurrentFiber(nextEffect); } </ins> const effectTag = nextEffect.effectTag; if (effectTag & (Update | Callback)) {


const MAX_SIZE = 500; const PAGE_SIZE = 50; <del> function createRecord<K, V>(key: K): EmptyRecord<K, V> { </del> <ins> function createRecord<K>(key: K): EmptyRecord<K> { </ins> return { status: Empty, suspender: null,


return newHead; } <del> function load<V>(emptyRecord: EmptyRecord, suspender: Promise<V>) { const pendingRecord: PendingRecord<V> = (emptyRecord: any); </del> <ins> function load<K, V>(emptyRecord: EmptyRecord<K>, suspender: Promise<V>) { const pendingRecord: PendingRecord<K, V> = (emptyRecord: any); </ins> pendingRecord.status = Pending; pendingRecord.suspender = suspender; suspender.then( value => { // Resource loaded successfully. <del> const resolvedRecord: ResolvedRecord<V> = (pendingRecord: any); </del> <ins> const resolvedRecord: ResolvedRecord<K, V> = (pendingRecord: any); </ins> resolvedRecord.status = Resolved; resolvedRecord.suspender = null; resolvedRecord.value = value;


var propName = propertyInfo.propertyName; // Must explicitly cast values for HAS_SIDE_EFFECTS-properties to the // property type before comparing; only `value` does and is string. <del> // Must set `value` property if it is not null and not yet set. </del> if (!propertyInfo.hasSideEffects || <del> ('' + node[propName]) !== ('' + value) || !node.hasAttribute(propertyInfo.attributeName)) { </del> <ins> ('' + node[propName]) !== ('' + value)) { </ins> // Contrary to `setAttribute`, object properties are properly // `toString`ed by IE8/9. node[propName] = value;


{isEditable ? ( <EditableValue  dataType={dataType}   initialValue={value}  overrideValueFn={((overrideValueFn: any): OverrideValueFn)} path={path}  initialValue={value}  /> ) : ( {displayValue}


do { lastID = internalGetID(current); current = current.parentNode; <del> invariant( current != null, 'findFirstReactDOMImpl(...): Unexpected detached subtree found when ' + 'traversing DOM from node `%s`.', nodeID ); </del> <ins> if (current == null) { // The passed-in node has been detached from the container it was // originally rendered into. return null; } </ins> } while (lastID !== reactRootID); if (current === containersByReactRootID[reactRootID]) {


Markdown is a simple way to format your text inline. For example, surrounding text with asterisks will make it emphasized. <del> First, add the third-party **Showdown** library to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground): </del> <ins> First, add the third-party library **marked** to your application. This is a JavaScript library which takes Markdown text and converts it to raw HTML. This requires a script tag in your head (which we have already included in the React playground): </ins> ```html{7} <!-- index.html -->


); } break; <ins> case 'option': transaction.getReactMountReady().enqueue( optionPostMount, this ); </ins> } return mountImage;


"private": true, "scripts": { "build": "cross-env NODE_ENV=production yarn run build:chrome && yarn run build:firefox && yarn run build:edge", <del> "build:dev": "cross-env NODE_ENV=development yarn run build:chrome && yarn run build:firefox && yarn run build:edge", </del> <ins> "build:dev": "cross-env NODE_ENV=development yarn run build:chrome:dev && yarn run build:firefox:dev && yarn run build:edge:dev", </ins> "build:chrome": "cross-env NODE_ENV=production node ./chrome/build", "build:chrome:crx": "cross-env NODE_ENV=production node ./chrome/build --crx", "build:chrome:dev": "cross-env NODE_ENV=development node ./chrome/build",


return markup; }, <ins> _constructComponent: function(publicProps, publicContext) { if (__DEV__) { ReactCurrentOwner.current = this; try { return this._constructComponentWithoutOwner(publicProps, publicContext); } finally { ReactCurrentOwner.current = null; } } else { return this._constructComponentWithoutOwner(publicProps, publicContext); } }, _constructComponentWithoutOwner: function(publicProps, publicContext) { var Component = this._currentElement.type; if (shouldConstruct(Component)) { return new Component(publicProps, publicContext, ReactUpdateQueue); } else { return Component(publicProps, publicContext, ReactUpdateQueue); } }, </ins> performInitialMountWithErrorHandling: function( renderedElement, nativeParent,


<script type="text/javascript" src="/react/js/react.js"></script> <script type="text/javascript" src="/react/js/JSXTransformer.js"></script> <script type="text/javascript" src="/react/js/live_editor.js"></script> <del> <script type="text/javascript" src="/react/js/showdown.js"></script> </del> </head> <body>


const elementType = getElementTypeForFiber(fiber); const {_debugOwner} = fiber; <del> const ownerID = _debugOwner != null ? getFiberIDThrows(_debugOwner) : 0; </del> <ins> // Ideally we should call getFiberIDThrows() for _debugOwner, // since owners are almost always higher in the tree (and so have already been processed), // but in some (rare) instances reported in open source, a descendant mounts before an owner. // Since this is a DEV only field it's probably okay to also just lazily generate and ID here if needed. // See https://github.com/facebook/react/issues/21445 const ownerID = _debugOwner != null ? getOrGenerateFiberID(_debugOwner) : 0; </ins> const parentID = parentFiber ? getFiberIDThrows(parentFiber) : 0; const displayNameStringID = getStringID(displayName);


 // // showdown.js -- A javascript port of Markdown. // // Copyright (c) 2007 John Fraser. // // Original Markdown Copyright (c) 2004-2005 John Gruber //   <http://daringfireball.net/projects/markdown/> // // Redistributable under a BSD-style open source license. // See license.txt for more information. // // The full source distribution is at: // //				A A L //				T C A //				T K B // //   <http://www.attacklab.net/> // // // Wherever possible, Showdown is a straight, line-by-line port // of the Perl version of Markdown. // // This is not a normal parser design; it's basically just a // series of string substitutions.  It's hard to read and // maintain this way,  but keeping Showdown close to the original // design makes it easier to port new features. // // More importantly, Showdown behaves like markdown.pl in most // edge cases.  So web applications can do client-side preview // in Javascript, and then build identical HTML on the server. // // This port needs the new RegExp functionality of ECMA 262, // 3rd Edition (i.e. Javascript 1.5).  Most modern web browsers // should do fine.  Even with the new regular expression features, // We do a lot of work to emulate Perl's regex functionality. // The tricky changes in this file mostly have the "attacklab:" // label.  Major or self-explanatory changes don't. // // Smart diff tools like Araxis Merge will be able to match up // this file with markdown.pl in a useful way.  A little tweaking // helps: in a copy of markdown.pl, replace "#" with "//" and // replace "$text" with "text".  Be sure to ignore whitespace // and line endings. // // // Showdown usage: // //   var text = "Markdown *rocks*."; // //   var converter = new Showdown.converter(); //   var html = converter.makeHtml(text); // //   alert(html); // // Note: move the sample code to the bottom of this // file before uncommenting it. // // // Showdown namespace // var Showdown = {}; // // converter // // Wraps all "globals" so that the only thing // exposed is makeHtml(). // Showdown.converter = function() { // // Globals: // // Global hashes, used by various utility routines var g_urls; var g_titles; var g_html_blocks; // Used to track when we're inside an ordered or unordered list // (see _ProcessListItems() for details): var g_list_level = 0; this.makeHtml = function(text) { // // Main function. The order in which other subs are called here is // essential. Link and image substitutions need to happen before // _EscapeSpecialCharsWithinTagAttributes(), so that any *'s or _'s in the  // and  tags get encoded. // // Clear the global hashes. If we don't clear these, you get conflicts // from other articles when generating a page which contains more than // one article (e.g. an index page that shows the N most recent // articles): g_urls = new Array(); g_titles = new Array(); g_html_blocks = new Array(); // attacklab: Replace ~ with ~T // This lets us use tilde as an escape char to avoid md5 hashes // The choice of character is arbitray; anything that isn't // magic in Markdown will work. text = text.replace(/~/g,"~T"); // attacklab: Replace $ with ~D // RegExp interprets $ as a special character // when it's in a replacement string text = text.replace(/$/g,"~D"); // Standardize line endings text = text.replace(/rn/g,"n"); // DOS to Unix text = text.replace(/r/g,"n"); // Mac to Unix // Make sure text begins and ends with a couple of newlines: text = "nn" + text + "nn"; // Convert all tabs to spaces. text = _Detab(text); // Strip any lines consisting only of spaces and tabs. // This makes subsequent regexen easier to write, because we can // match consecutive blank lines with /n+/ instead of something // contorted like /[ t]*n+/ . text = text.replace(/^[ t]+$/mg,""); // Turn block-level HTML blocks into hash entries text = _HashHTMLBlocks(text); // Strip link definitions, store in hashes. text = _StripLinkDefinitions(text); text = _RunBlockGamut(text); text = _UnescapeSpecialChars(text); // attacklab: Restore dollar signs text = text.replace(/~D/g,"$$"); // attacklab: Restore tildes text = text.replace(/~T/g,"~"); return text; } var _StripLinkDefinitions = function(text) { // // Strips link definitions from text, stores the URLs and titles in // hash references. // // Link defs are in the form: ^[id]: url "optional title" /* var text = text.replace(/ ^[ ]{0,3}[(.+)]:  // id = $1  attacklab: g_tab_width - 1 [ t]* n?				// maybe *one* newline [ t]* <?(S+?)>?			// url = $2 [ t]* n?				// maybe one newline [ t]* (?: (n*)				// any lines skipped = $3 attacklab: lookbehind removed ["(] (.+?)				// title = $4 [")] [ t]* )?					// title is optional (?:n+|$) /gm, function(){...}); */ var text = text.replace(/^[ ]{0,3}[(.+)]:[ t]*n?[ t]*<?(S+?)>?[ t]*n?[ t]*(?:(n*)["(](.+?)[")][ t]*)?(?:n+|Z)/gm, function (wholeMatch,m1,m2,m3,m4) { m1 = m1.toLowerCase(); g_urls[m1] = _EncodeAmpsAndAngles(m2);  // Link IDs are case-insensitive if (m3) { // Oops, found blank lines, so it's not a title. // Put back the parenthetical statement we stole. return m3+m4; } else if (m4) { g_titles[m1] = m4.replace(/"/g,"""); } // Completely remove the definition from the text return ""; } ); return text; } var _HashHTMLBlocks = function(text) { // attacklab: Double up blank lines to reduce lookaround text = text.replace(/n/g,"nn"); // Hashify HTML blocks: // We only want to do this for block-level HTML tags, such as headers, // lists, and tables. That's because we still want to wrap
s around // "paragraphs" that are wrapped in non-block-level tags, such as anchors, // phrase emphasis, and spans. The list of tags we're looking for is // hard-coded: var block_tags_a = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del" var block_tags_b = "p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math" // First, look for nested blocks, e.g.: //
 //
 //     tags for inner block must be indented. //
 //
 // // The outermost tags must start at the left margin for this to match, and // the inner nested divs must be indented. // We need to do this before the next, more liberal match, because the next // match will start at the first `<div>` and stop at the first `</div>`. // attacklab: This regex can be expensive when it fails. /* var text = text.replace(/ (						// save in $1 ^					// start of line  (with /m) <($block_tags_a)	// start tag = $2 b					// word break // attacklab: hack around khtml/pcre bug... [^r]*?n			// any number of lines, minimally matching </2>				// the matching end tag [ t]*				// trailing spaces/tabs (?=n+)				// followed by a newline )						// attacklab: there are sentinel newlines at end of document /gm,function(){...}}; */ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math|ins|del)b[^r]*?n</2>[ t]*(?=n+))/gm,hashElement); // // Now match more liberally, simply from `n<tag>` to `</tag>n` // /* var text = text.replace(/ (						// save in $1 ^					// start of line  (with /m) <($block_tags_b)	// start tag = $2 b					// word break // attacklab: hack around khtml/pcre bug... [^r]*?				// any number of lines, minimally matching .*</2>				// the matching end tag [ t]*				// trailing spaces/tabs (?=n+)				// followed by a newline )						// attacklab: there are sentinel newlines at end of document /gm,function(){...}}; */ text = text.replace(/^(<(p|div|h[1-6]|blockquote|pre|table|dl|ol|ul|script|noscript|form|fieldset|iframe|math)b[^r]*?.*</2>[ t]*(?=n+)n)/gm,hashElement); // Special case just for
. It was easier to make a special case than // to make the other regex more complicated. /* text = text.replace(/ (						// save in $1 nn				// Starting after a blank line [ ]{0,3} (<(hr)				// start tag = $2 b					// word break ([^<>])*?			// /?>)				// the matching end tag [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(n[ ]{0,3}(<(hr)b([^<>])*?/?>)[ t]*(?=n{2,}))/g,hashElement); // Special case for standalone HTML comments: /* text = text.replace(/ (						// save in $1 nn				// Starting after a blank line [ ]{0,3}			// attacklab: g_tab_width - 1 <! (--[^r]*?--s*)+ > [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(nn[ ]{0,3}<!(--[^r]*?--s*)+>[ t]*(?=n{2,}))/g,hashElement); // PHP and ASP-style processor instructions (<?...?> and <%...%>) /* text = text.replace(/ (?: nn				// Starting after a blank line ) (						// save in $1 [ ]{0,3}			// attacklab: g_tab_width - 1 (?: <([?%])			// $2 [^r]*? 2> ) [ t]* (?=n{2,})			// followed by a blank line ) /g,hashElement); */ text = text.replace(/(?:nn)([ ]{0,3}(?:<([?%])[^r]*?2>)[ t]*(?=n{2,}))/g,hashElement); // attacklab: Undo double lines (see comment at top of this function) text = text.replace(/nn/g,"n"); return text; } var hashElement = function(wholeMatch,m1) { var blockText = m1; // Undo double lines blockText = blockText.replace(/nn/g,"n"); blockText = blockText.replace(/^n/,""); // strip trailing blank lines blockText = blockText.replace(/n+$/g,""); // Replace the element text with a marker ("~KxK" where x is its key) blockText = "nn~K" + (g_html_blocks.push(blockText)-1) + "Knn"; return blockText; }; var _RunBlockGamut = function(text) { // // These are all the transformations that form block-level // tags like paragraphs, headers, and list items. // text = _DoHeaders(text); // Do Horizontal Rules: var key = hashBlock("
"); text = text.replace(/^[ ]{0,2}([ ]?*[ ]?){3,}[ t]*$/gm,key); text = text.replace(/^[ ]{0,2}([ ]?-[ ]?){3,}[ t]*$/gm,key); text = text.replace(/^[ ]{0,2}([ ]?_[ ]?){3,}[ t]*$/gm,key); text = _DoLists(text); text = _DoCodeBlocks(text); text = _DoBlockQuotes(text); // We already ran _HashHTMLBlocks() before, in Markdown(), but that // was to escape raw HTML in the original Markdown source. This time, // we're escaping the markup we've just created, so that we don't wrap //
 tags around block-level tags. text = _HashHTMLBlocks(text); text = _FormParagraphs(text); return text; } var _RunSpanGamut = function(text) { // // These are all the transformations that occur *within* block-level // tags like paragraphs, headers, and list items. // text = _DoCodeSpans(text); text = _EscapeSpecialCharsWithinTagAttributes(text); text = _EncodeBackslashEscapes(text); // Process anchor and image tags. Images must come first, // because ![foo][f] looks like an anchor. text = _DoImages(text); text = _DoAnchors(text); // Make links out of things like `<http://example.com/>` // Must come after _DoAnchors(), because you can use < and > // delimiters in inline links like [this](<url>). text = _DoAutoLinks(text); text = _EncodeAmpsAndAngles(text); text = _DoItalicsAndBold(text); // Do hard breaks: text = text.replace(/  +n/g,"
n"); return text; } var _EscapeSpecialCharsWithinTagAttributes = function(text) { // // Within tags -- meaning between < and > -- encode [ ` * _] so they // don't conflict with their use in Markdown for code, italics and strong. // // Build a regex to find HTML tags and comments.  See Friedl's // "Mastering Regular Expressions", 2nd Ed., pp. 200-201. var regex = /(<[a-z/!$]("[^"]*"|'[^']*'|[^'">])*>|<!(--.*?--s*)+>)/gi; text = text.replace(regex, function(wholeMatch) { var tag = wholeMatch.replace(/(.)</?code>(?=.)/g,"$1`"); tag = escapeCharacters(tag,"`*_"); return tag; }); return text; } var _DoAnchors = function(text) { // // Turn Markdown link shortcuts into XHTML  tags. // // // First, handle reference-style links: [link text] [id] // /* text = text.replace(/ (							// wrap whole match in $1 [ ( (?: [[^]]*]		// allow brackets nested one level | [^[]			// or anything else )* ) ] [ ]?					// one optional space (?:n[ ]*)?				// one optional newline followed by spaces [ (.*?)					// id = $3 ] )()()()()					// pad remaining backreferences /g,_DoAnchors_callback); */ text = text.replace(/([((?:[[^]]*]|[^[]])*)][ ]?(?:n[ ]*)?[(.*?)])()()()()/g,writeAnchorTag); // // Next, inline-style links: [link text](url "optional title") // /* text = text.replace(/ (						// wrap whole match in $1 [ ( (?: [[^]]*]	// allow brackets nested one level | [^[]]			// or anything else ) ) ] (						// literal paren [ t]* ()						// no id, so leave $3 empty <?(.*?)>?				// href = $4 [ t]* (						// $5 (['"])				// quote char = $6 (.*?)				// Title = $7 6					// matching quote [ t]*				// ignore any spaces/tabs between closing quote and ) )?						// title is optional ) ) /g,writeAnchorTag); */ text = text.replace(/([((?:[[^]]*]|[^[]])*)]([ t]*()<?(.*?)>?[ t]*((['"])(.*?)6[ t]*)?))/g,writeAnchorTag); // // Last, handle reference-style shortcuts: [link text] // These must come last in case you've also got [link test][1] // or [link test](/foo) // /* text = text.replace(/ (		 					// wrap whole match in $1 [ ([^[]]+)				// link text = $2; can't contain '[' or ']' ] )()()()()()					// pad rest of backreferences /g, writeAnchorTag); */ text = text.replace(/([([^[]]+)])()()()()()/g, writeAnchorTag); return text; } var writeAnchorTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { if (m7 == undefined) m7 = ""; var whole_match = m1; var link_text   = m2; var link_id	 = m3.toLowerCase(); var url		= m4; var title	= m7; if (url == "") { if (link_id == "") { // lower-case and turn embedded newlines into spaces link_id = link_text.toLowerCase().replace(/ ?n/g," "); } url = "#"+link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } } else { if (whole_match.search(/(s*)$/m)>-1) { // Special case for explicit empty url url = ""; } else { return whole_match; } } } url = escapeCharacters(url,"*_"); var result = "" + link_text + ""; return result; } var _DoImages = function(text) { // // Turn Markdown image shortcuts into  tags. // // // First, handle reference-style labeled images: ![alt text][id] // /* text = text.replace(/ (						// wrap whole match in $1 ![ (.*?)				// alt text = $2 ] [ ]?				// one optional space (?:n[ ]*)?			// one optional newline followed by spaces [ (.*?)				// id = $3 ] )()()()()				// pad rest of backreferences /g,writeImageTag); */ text = text.replace(/(![(.*?)][ ]?(?:n[ ]*)?[(.*?)])()()()()/g,writeImageTag); // // Next, handle inline images:  ![alt text](url "optional title") // Don't forget: encode * and _ /* text = text.replace(/ (						// wrap whole match in $1 ![ (.*?)				// alt text = $2 ] s?					// One optional whitespace character (					// literal paren [ t]* ()					// no id, so leave $3 empty <?(S+?)>?			// src url = $4 [ t]* (					// $5 (['"])			// quote char = $6 (.*?)			// title = $7 6				// matching quote [ t]* )?					// title is optional ) ) /g,writeImageTag); */ text = text.replace(/(![(.*?)]s?([ t]*()<?(S+?)>?[ t]*((['"])(.*?)6[ t]*)?))/g,writeImageTag); return text; } var writeImageTag = function(wholeMatch,m1,m2,m3,m4,m5,m6,m7) { var whole_match = m1; var alt_text   = m2; var link_id	 = m3.toLowerCase(); var url		= m4; var title	= m7; if (!title) title = ""; if (url == "") { if (link_id == "") { // lower-case and turn embedded newlines into spaces link_id = alt_text.toLowerCase().replace(/ ?n/g," "); } url = "#"+link_id; if (g_urls[link_id] != undefined) { url = g_urls[link_id]; if (g_titles[link_id] != undefined) { title = g_titles[link_id]; } } else { return whole_match; } } alt_text = alt_text.replace(/"/g,"""); url = escapeCharacters(url,"*_"); var result = ""; return result; } var _DoHeaders = function(text) { // Setext-style headers: //	Header 1 //	======== // //	Header 2 //	-------- // text = text.replace(/^(.+)[ t]*n=+[ t]*n+/gm, function(wholeMatch,m1){return hashBlock('
' + _RunSpanGamut(m1) + "
");}); text = text.replace(/^(.+)[ t]*n-+[ t]*n+/gm, function(matchFound,m1){return hashBlock('
' + _RunSpanGamut(m1) + "
");}); // atx-style headers: //  # Header 1 //  ## Header 2 //  ## Header 2 with closing hashes ## //  ... //  ###### Header 6 // /* text = text.replace(/ ^(#{1,6})				// $1 = string of #'s [ t]* (.+?)					// $2 = Header text [ t]* #*						// optional closing #'s (not counted) n+ /gm, function() {...}); */ text = text.replace(/^(#{1,6})[ t]*(.+?)[ t]*#*n+/gm, function(wholeMatch,m1,m2) { var h_level = m1.length; return hashBlock("<h" + h_level + ' id="' + headerId(m2) + '">' + _RunSpanGamut(m2) + "</h" + h_level + ">"); }); function headerId(m) { return m.replace(/[^w]/g, '').toLowerCase(); } return text; } // This declaration keeps Dojo compressor from outputting garbage: var _ProcessListItems; var _DoLists = function(text) { // // Form HTML ordered (numbered) and unordered (bulleted) lists. // // attacklab: add sentinel to hack around khtml/safari bug: // http://bugs.webkit.org/show_bug.cgi?id=11231 text += "~0"; // Re-usable pattern to match any entirel ul or ol list: /* var whole_list = / (									// $1 = whole list (								// $2 [ ]{0,3}					// attacklab: g_tab_width - 1 ([*+-]|d+[.])				// $3 = first list item marker [ t]+ ) [^r]+? (								// $4 ~0							// sentinel for workaround; should be $ | n{2,} (?=S) (?!							// Negative lookahead for another list item marker [ t]* (?:[*+-]|d+[.])[ t]+ ) ) )/g */ var whole_list = /^(([ ]{0,3}([*+-]|d+[.])[ t]+)[^r]+?(~0|n{2,}(?=S)(?![ t]*(?:[*+-]|d+[.])[ t]+)))/gm; if (g_list_level) { text = text.replace(whole_list,function(wholeMatch,m1,m2) { var list = m1; var list_type = (m2.search(/[*+-]/g)>-1) ? "ul" : "ol"; // Turn double returns into triple returns, so that we can make a // paragraph for the last item in a list, if necessary: list = list.replace(/n{2,}/g,"nnn");; var result = _ProcessListItems(list); // Trim any trailing whitespace, to put the closing `</$list_type>` // up on the preceding line, to get it past the current stupid // HTML block parser. This is a hack to work around the terrible // hack that is the HTML block parser. result = result.replace(/s+$/,""); result = "<"+list_type+">" + result + "</"+list_type+">n"; return result; }); } else { whole_list = /(nn|^n?)(([ ]{0,3}([*+-]|d+[.])[ t]+)[^r]+?(~0|n{2,}(?=S)(?![ t]*(?:[*+-]|d+[.])[ t]+)))/g; text = text.replace(whole_list,function(wholeMatch,m1,m2,m3) { var runup = m1; var list = m2; var list_type = (m3.search(/[*+-]/g)>-1) ? "ul" : "ol"; // Turn double returns into triple returns, so that we can make a // paragraph for the last item in a list, if necessary: var list = list.replace(/n{2,}/g,"nnn");; var result = _ProcessListItems(list); result = runup + "<"+list_type+">n" + result + "</"+list_type+">n"; return result; }); } // attacklab: strip sentinel text = text.replace(/~0/,""); return text; } _ProcessListItems = function(list_str) { // //  Process the contents of a single ordered or unordered list, splitting it //  into individual list items. // // The $g_list_level global keeps track of when we're inside a list. // Each time we enter a list, we increment it; when we leave a list, // we decrement. If it's zero, we're not in a list anymore. // // We do this because when we're not inside a list, we want to treat // something like this: // //    I recommend upgrading to version //    8. Oops, now this line is treated //    as a sub-list. // // As a single paragraph, despite the fact that the second line starts // with a digit-period-space sequence. // // Whereas when we're inside a list (or sub-list), that line will be // treated as the start of a sub-list. What a kludge, huh? This is // an aspect of Markdown's syntax that's hard to parse perfectly // without resorting to mind-reading. Perhaps the solution is to // change the syntax rules such that sub-lists must start with a // starting cardinal number; e.g. "1." or "a.". g_list_level++; // trim trailing blank lines: list_str = list_str.replace(/n{2,}$/,"n"); // attacklab: add sentinel to emulate z list_str += "~0"; /* list_str = list_str.replace(/ (n)?							// leading line = $1 (^[ t]*)						// leading whitespace = $2 ([*+-]|d+[.]) [ t]+			// list marker = $3 ([^r]+?						// list item text   = $4 (n{1,2})) (?= n* (~0 | 2 ([*+-]|d+[.]) [ t]+)) /gm, function(){...}); */ list_str = list_str.replace(/(n)?(^[ t]*)([*+-]|d+[.])[ t]+([^r]+?(n{1,2}))(?=n*(~0|2([*+-]|d+[.])[ t]+))/gm, function(wholeMatch,m1,m2,m3,m4){ var item = m4; var leading_line = m1; var leading_space = m2; if (leading_line || (item.search(/n{2,}/)>-1)) { item = _RunBlockGamut(_Outdent(item)); } else { // Recursion for sub-lists: item = _DoLists(_Outdent(item)); item = item.replace(/n$/,""); // chomp(item) item = _RunSpanGamut(item); } return  "
" + item + "
n"; } ); // attacklab: strip sentinel list_str = list_str.replace(/~0/g,""); g_list_level--; return list_str; } var _DoCodeBlocks = function(text) { // //  Process Markdown `<pre><code>` blocks. // /* text = text.replace(text, /(?:nn|^) (								// $1 = the code block -- one or more lines, starting with a space/tab (?: (?:[ ]{4}|t)			// Lines must start with a tab or a tab-width of spaces - attacklab: g_tab_width .*n+ )+ ) (n*[ ]{0,3}[^ tn]|(?=~0))	// attacklab: g_tab_width /g,function(){...}); */ // attacklab: sentinel workarounds for lack of A and Z, safarikhtml bug text += "~0"; text = text.replace(/(?:nn|^)((?:(?:[ ]{4}|t).*n+)+)(n*[ ]{0,3}[^ tn]|(?=~0))/g, function(wholeMatch,m1,m2) { var codeblock = m1; var nextChar = m2; codeblock = _EncodeCode( _Outdent(codeblock)); codeblock = _Detab(codeblock); codeblock = codeblock.replace(/^n+/g,""); // trim leading newlines codeblock = codeblock.replace(/n+$/g,""); // trim trailing whitespace codeblock = "
" + codeblock + "n
"; return hashBlock(codeblock) + nextChar; } ); // attacklab: strip sentinel text = text.replace(/~0/,""); return text; } var hashBlock = function(text) { text = text.replace(/(^n+|n+$)/g,""); return "nn~K" + (g_html_blocks.push(text)-1) + "Knn"; } var _DoCodeSpans = function(text) { // //   *  Backtick quotes are used for  spans. // //   *  You can use multiple backticks as the delimiters if you want to //	 include literal backticks in the code span. So, this input: // //		 Just type ``foo `bar` baz`` at the prompt. // //	   Will translate to: // //
Just type foo `bar` baz at the prompt.
 // //	There's no arbitrary limit to the number of backticks you //	can use as delimters. If you need three consecutive backticks //	in your code, use four for delimiters, etc. // //  *  You can use spaces to get literal backticks at the edges: // //		 ... type `` `bar` `` ... // //	   Turns to: // //		 ... type `bar` ... // /* text = text.replace(/ (^|[^])					// Character before opening ` can't be a backslash (`+)						// $2 = Opening run of ` (							// $3 = The code block [^r]*? [^`]					// attacklab: work around lack of lookbehind ) 2							// Matching closer (?!`) /gm, function(){...}); */ text = text.replace(/(^|[^])(`+)([^r]*?[^`])2(?!`)/gm, function(wholeMatch,m1,m2,m3,m4) { var c = m3; c = c.replace(/^([ t]*)/g,"");	// leading whitespace c = c.replace(/[ t]*$/g,"");	// trailing whitespace c = _EncodeCode(c); return m1+""+c+""; }); return text; } var _EncodeCode = function(text) { // // Encode/escape certain characters inside Markdown code runs. // The point is that in code, these characters are literals, // and lose their special Markdown meanings. // // Encode all ampersands; HTML entities are not // entities within a Markdown code span. text = text.replace(/&/g,"&"); // Do the angle bracket song and dance: text = text.replace(/</g,"<"); text = text.replace(/>/g,">"); // Now, escape characters that are magic in Markdown: text = escapeCharacters(text,"*_{}[]",false); // jj the line above breaks this: //--- //* Item //   1. Subitem //            special char: * //--- return text; } var _DoItalicsAndBold = function(text) { //  must go first: text = text.replace(/(**|__)(?=S)([^r]*?S[*_]*)1/g, "$2"); text = text.replace(/(*|_)(?=S)([^r]*?S)1/g, "$2"); return text; } var _DoBlockQuotes = function(text) { /* text = text.replace(/ (								// Wrap whole match in $1 ( ^[ t]*>[ t]?			// '>' at the start of a line .+n					// rest of the first line (.+n)*					// subsequent consecutive lines n*						// blanks )+ ) /gm, function(){...}); */ text = text.replace(/((^[ t]*>[ t]?.+n(.+n)*n*)+)/gm, function(wholeMatch,m1) { var bq = m1; // attacklab: hack around Konqueror 3.5.4 bug: // "----------bug".replace(/^-/g,"") == "bug" bq = bq.replace(/^[ t]*>[ t]?/gm,"~0");	// trim one level of quoting // attacklab: clean up hack bq = bq.replace(/~0/g,""); bq = bq.replace(/^[ t]+$/gm,"");		// trim whitespace-only lines bq = _RunBlockGamut(bq);				// recurse bq = bq.replace(/(^|n)/g,"$1  "); // These leading spaces screw with
 content, so we need to fix that: bq = bq.replace( /(s*
[^r]+?
)/gm, function(wholeMatch,m1) { var pre = m1; // attacklab: hack around Konqueror 3.5.4 bug: pre = pre.replace(/^  /mg,"~0"); pre = pre.replace(/~0/g,""); return pre; }); return hashBlock("
n" + bq + "n
"); }); return text; } var _FormParagraphs = function(text) { // //  Params: //    $text - string to process with html
 tags // // Strip leading and trailing lines: text = text.replace(/^n+/g,""); text = text.replace(/n+$/g,""); var grafs = text.split(/n{2,}/g); var grafsOut = new Array(); // // Wrap
 tags. // var end = grafs.length; for (var i=0; i<end; i++) { var str = grafs[i]; // if this is an HTML marker, copy it if (str.search(/~K(d+)K/g) >= 0) { grafsOut.push(str); } else if (str.search(/S/) >= 0) { str = _RunSpanGamut(str); str = str.replace(/^([ t]*)/g,"
"); str += "
" grafsOut.push(str); } } // // Unhashify HTML blocks // end = grafsOut.length; for (var i=0; i<end; i++) { // if this is a marker for an html block... while (grafsOut[i].search(/~K(d+)K/) >= 0) { var blockText = g_html_blocks[RegExp.$1]; blockText = blockText.replace(/$/g,"$$$$"); // Escape any dollar signs grafsOut[i] = grafsOut[i].replace(/~Kd+K/,blockText); } } return grafsOut.join("nn"); } var _EncodeAmpsAndAngles = function(text) { // Smart processing for ampersands and angle brackets that need to be encoded. // Ampersand-encoding based entirely on Nat Irons's Amputator MT plugin: //   http://bumppo.net/projects/amputator/ text = text.replace(/&(?!#?[xX]?(?:[0-9a-fA-F]+|w+);)/g,"&"); // Encode naked <'s text = text.replace(/<(?![a-z/?$!])/gi,"<"); return text; } var _EncodeBackslashEscapes = function(text) { // //   Parameter:  String. //   Returns:	The string, with after processing the following backslash //			   escape sequences. // // attacklab: The polite way to do this is with the new // escapeCharacters() function: // // 	text = escapeCharacters(text,"",true); // 	text = escapeCharacters(text,"`*_{}[]()>#+-.!",true); // // ...but we're sidestepping its use of the (slow) RegExp constructor // as an optimization for Firefox.  This function gets called a LOT. text = text.replace(/()/g,escapeCharacters_callback); text = text.replace(/([`*_{}[]()>#+-.!])/g,escapeCharacters_callback); return text; } var _DoAutoLinks = function(text) { text = text.replace(/<((https?|ftp|dict):[^'">s]+)>/gi,"$1"); // Email addresses: <address@domain.foo> /* text = text.replace(/ < (?:mailto:)? ( [-.w]+ @ [-a-z0-9]+(.[-a-z0-9]+)*.[a-z]+ ) > /gi, _DoAutoLinks_callback()); */ text = text.replace(/<(?:mailto:)?([-.w]+@[-a-z0-9]+(.[-a-z0-9]+)*.[a-z]+)>/gi, function(wholeMatch,m1) { return _EncodeEmailAddress( _UnescapeSpecialChars(m1) ); } ); return text; } var _EncodeEmailAddress = function(addr) { // //  Input: an email address, e.g. "foo@example.com" // //  Output: the email address as a mailto link, with each character //	of the address encoded as either a decimal or hex entity, in //	the hopes of foiling most address harvesting spam bots. E.g.: // //	foo //	   @example.com // //  Based on a filter by Matthew Wickline, posted to the BBEdit-Talk //  mailing list: <http://tinyurl.com/yu7ue> // // attacklab: why can't javascript speak hex? function char2hex(ch) { var hexDigits = '0123456789ABCDEF'; var dec = ch.charCodeAt(0); return(hexDigits.charAt(dec>>4) + hexDigits.charAt(dec&15)); } var encode = [ function(ch){return "&#"+ch.charCodeAt(0)+";";}, function(ch){return "&#x"+char2hex(ch)+";";}, function(ch){return ch;} ]; addr = "mailto:" + addr; addr = addr.replace(/./g, function(ch) { if (ch == "@") { // this *must* be encoded. I insist. ch = encode[Math.floor(Math.random()*2)](ch); } else if (ch !=":") { // leave ':' alone (to spot mailto: later) var r = Math.random(); // roughly 10% raw, 45% hex, 45% dec ch =  ( r > .9  ?	encode[2](ch)   : r > .45 ?	encode[1](ch)   : encode[0](ch) ); } return ch; }); addr = "" + addr + ""; addr = addr.replace(/">.+:/g,"">"); // strip the mailto: from the visible part return addr; } var _UnescapeSpecialChars = function(text) { // // Swap back in all the special characters we've hidden. // text = text.replace(/~E(d+)E/g, function(wholeMatch,m1) { var charCodeToReplace = parseInt(m1); return String.fromCharCode(charCodeToReplace); } ); return text; } var _Outdent = function(text) { // // Remove one level of line-leading tabs or spaces // // attacklab: hack around Konqueror 3.5.4 bug: // "----------bug".replace(/^-/g,"") == "bug" text = text.replace(/^(t|[ ]{1,4})/gm,"~0"); // attacklab: g_tab_width // attacklab: clean up hack text = text.replace(/~0/g,"") return text; } var _Detab = function(text) { // attacklab: Detab's completely rewritten for speed. // In perl we could fix it by anchoring the regexp with G. // In javascript we're less fortunate. // expand first n-1 tabs text = text.replace(/t(?=t)/g,"    "); // attacklab: g_tab_width // replace the nth with two sentinels text = text.replace(/t/g,"~A~B"); // use the sentinel to anchor our regex so it doesn't explode text = text.replace(/~B(.+?)~A/g, function(wholeMatch,m1,m2) { var leadingText = m1; var numSpaces = 4 - leadingText.length % 4;  // attacklab: g_tab_width // there *must* be a better way to do this: for (var i=0; i<numSpaces; i++) leadingText+=" "; return leadingText; } ); // clean up sentinels text = text.replace(/~A/g,"    ");  // attacklab: g_tab_width text = text.replace(/~B/g,""); return text; } // //  attacklab: Utility functions // var escapeCharacters = function(text, charsToEscape, afterBackslash) { // First we have to escape the escape characters so that // we can build a character class out of them var regexString = "([" + charsToEscape.replace(/([[]])/g,"$1") + "])"; if (afterBackslash) { regexString = "" + regexString; } var regex = new RegExp(regexString,"g"); text = text.replace(regex,escapeCharacters_callback); return text; } var escapeCharacters_callback = function(wholeMatch,m1) { var charCodeToEscape = m1.charCodeAt(0); return "~E"+charCodeToEscape+"E"; } } // end of Showdown.converter // export if (typeof exports != 'undefined') exports.Showdown = Showdown;   No newline at end of file


: emptyObject; const instance = new ctor(props, context); adoptClassInstance(workInProgress, instance); <del> checkClassInstance(workInProgress); </del> // Cache unmasked context so we can avoid recreating masked context unless necessary. // ReactFiberContext usually updates this cache but can't for newly-created instances.


that support `*.tmLanguage`. * Linting provides accurate line numbers after compiling without sourcemaps. * Elements use standard scoping so linters can find usage of out-of-scope components. <ins> ### Debugging [React Developer Tools](https://github.com/facebook/react-devtools) is a [Chrome extension](https://chrome.google.com/webstore/detail/react-developer-tools/fmkadmapgofadopljbjfkapdkoienihi?hl=en) that allows you to inspect the React component hierarchy in the Chrome Developer Tools. </ins>


} export function createLaneMap<T>(initial: T): LaneMap<T> { <del> return new Array(TotalLanes).fill(initial); </del> <ins> // Intentionally pushing one by one. // https://v8.dev/blog/elements-kinds#avoid-creating-holes const laneMap = []; for (let i = 0; i < TotalLanes; i++) { laneMap.push(initial); } return laneMap; </ins> } export function markRootUpdated(


echo "Only docs were updated, stopping build process." exit fi <del> npm install -g npm </del> <ins> npm install -g npm@latest-2 </ins> script: - | if [ "$TEST_TYPE" = build_website ]; then


var Component = this._currentElement.type; // Initialize the public class <del> var inst; </del> <ins> var inst = this._constructComponent(publicProps, publicContext); </ins> var renderedElement; <del> if (Component.prototype && Component.prototype.isReactComponent) { if (__DEV__) { ReactCurrentOwner.current = this; try { inst = new Component(publicProps, publicContext, ReactUpdateQueue); } finally { ReactCurrentOwner.current = null; } } else { inst = new Component(publicProps, publicContext, ReactUpdateQueue); } } else { if (__DEV__) { ReactCurrentOwner.current = this; try { inst = Component(publicProps, publicContext, ReactUpdateQueue); } finally { ReactCurrentOwner.current = null; } } else { inst = Component(publicProps, publicContext, ReactUpdateQueue); } if (inst == null || inst.render == null) { renderedElement = inst; warnIfInvalidElement(Component, renderedElement); invariant( inst === null || inst === false || ReactElement.isValidElement(inst), '%s(...): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component' ); inst = new StatelessComponent(Component); } </del> <ins> // Support functional components if (!shouldConstruct(Component) && (inst == null || inst.render == null)) { renderedElement = inst; warnIfInvalidElement(Component, renderedElement); invariant( inst === null || inst === false || ReactElement.isValidElement(inst), '%s(...): A valid React element (or null) must be returned. You may have ' + 'returned undefined, an array or some other invalid object.', Component.displayName || Component.name || 'Component' ); inst = new StatelessComponent(Component); </ins> } if (__DEV__) {


items: - id: flux-overview title: Flux Overview <ins> href: http://facebook.github.io/flux/docs/overview.html </ins> - id: flux-todo-list title: Flux TodoMVC Tutorial <ins> href: http://facebook.github.io/flux/docs/todo-list.html </ins>


const Resolved = 2; const Rejected = 3; <del> type EmptyRecord<K, V> = {| </del> <ins> type EmptyRecord<K> = {| </ins> status: 0, suspender: null, key: K, value: null, error: null, <del> next: Record<K, V> | null, previous: Record<K, V> | null, </del> <ins> next: any, // TODO: (issue #12941) previous: any, // TODO: (issue #12941) /** * Proper types would be something like this: * next: Record<K, V> | null, * previous: Record<K, V> | null, */ </ins> |}; type PendingRecord<K, V> = {| status: 1, <del> suspender: Promise<K, V>, </del> <ins> suspender: Promise<V>, </ins> key: K, value: null, error: null, <del> next: Record<K, V> | null, previous: Record<K, V> | null, </del> <ins> next: any, // TODO: (issue #12941) previous: any, // TODO: (issue #12941) /** * Proper types would be something like this: * next: Record<K, V> | null, * previous: Record<K, V> | null, */ </ins> |}; type ResolvedRecord<K, V> = {|


export const enableSelectiveHydration = false; export const enableChunksAPI = false; export const exposeConcurrentModeAPIs = __EXPERIMENTAL__; <del> export const warnAboutShorthandPropertyCollision = false; </del> <ins> export const warnAboutShorthandPropertyCollision = true; </ins> export const enableSchedulerDebugging = false; export const debugRenderPhaseSideEffectsForStrictMode = true; export const disableJavaScriptURLs = false;


--- id: flux-todo-list title: Flux TodoMVC Tutorial <del> prev: flux-overview.html </del> --- <del> To demonstrate the Flux architecture with some example code, let's take on the classic TodoMVC application. The entire application is available in the Flux GitHub repo within the [flux-todomvc](https://github.com/facebook/flux/tree/master/examples/flux-todomvc) example directory, but let's walk through the development of it a step at a time. To begin, we'll need some boilerplate and get up and running with a module system. Node's module system, based on CommonJS, will fit the bill very nicely and we can build off of [react-boilerplate](https://github.com/petehunt/react-boilerplate) to get up and running quickly. Assuming you have npm installed, simply clone the react-boilerplate code from GitHub, and navigate into the resulting directory in Terminal (or whatever CLI application you like). Next run the npm scripts to get up and running: `npm install`, then `npm run build`, and lastly `npm start` to continuously build using Browserify. The TodoMVC example has all this built into it as well, but if you're starting with react-boilerplate make sure you edit your package.json file to match the file structure and dependencies described in the TodoMVC example's [package.json](https://github.com/facebook/flux/tree/master/examples/flux-todomvc/package.json), or else your code won't match up with the explanations below. Source Code Structure --------------------- The resulting index.js file may be used as the entry point into our app, but we'll put most of our code in a 'js' directory. Let's let Browserify do its thing, and now we'll open a new tab in Terminal (or a GUI file browser) to look at the directory. It should look something like this: ``` myapp | + ... + js | + app.js + bundle.js // generated by Browserify whenever we make changes. + index.html + ... ``` Next we'll dive into the js directory, and layout our application's primary directory structure: ``` myapp | + ... + js | + actions + components // all React components, both views and controller-views + constants + dispatcher + stores + app.js + bundle.js + index.html + ... ``` Using the Dispatcher -------------------- We'll use the dispatcher from the [Flux GitHub repository](https://github.com/facebook/flux), but let's go over how to get it into our project, how it works and how we'll use it. The dispatcher's source code is written in [ECMAScript 6](https://github.com/lukehoban/es6features), the future version of JavaScript.  To use the future of JS in today's browser's we need to transpile it back to a version of JS that browsers can use.  We perform this build step, transpiling from ES6 into common JavaScript, using npm. You can get up and running with the dispatcher in a variety of ways, but perhaps the simplest is to use [Michael Jackson](https://twitter.com/mjackson)'s npm module version of the Flux project, called [react-dispatcher](https://www.npmjs.org/package/react-dispatcher): ``` npm install react-dispatcher ``` Afterward, you can require the dispatcher in your project's modules like so: ```javascript var Dispatcher = require('Flux').Dispatcher; ``` Alternatively, you can clone the Flux repo, run the Gulp-based build script with `npm install`, and then simply copy the dispatcher and invariant modules located inside flux/lib/ to the dispatcher directory for your project.  This the what we did in the [example code](https://github.com/facebook/flux/tree/master/examples/flux-todomvc/js/dispatcher). The two most important methods that the dispatcher exposes publically are register() and dispatch().  We'll use register() within our stores to register each store's callback. We'll use dispatch() within our action creators to trigger the invocation of the callbacks. ```javascript class Dispatcher { constructor() { this._callbacks = {}; this._isPending = {}; this._isHandled = {}; this._isDispatching = false; this._pendingPayload = null; } /** * Registers a callback to be invoked with every dispatched payload. * * @param {function} callback * @return {string} */ register(callback) { var id = _prefix + _lastID++; this._callbacks[id] = callback; return id; } // ... /** * Dispatches a payload to all registered callbacks. * * @param {object} payload */ dispatch(payload) { invariant( !this._isDispatching, 'Dispatch.dispatch(...): Cannot dispatch in the middle of a dispatch.' ); this._startDispatching(payload); try { for (var id in this._callbacks) { if (this._isPending[id]) { continue; } this._invokeCallback(id); } } finally { this._stopDispatching(); } } // ... _invokeCallback(id) { this._isPending[id] = true; this._callbacks[id](this._pendingPayload); this._isHandled[id] = true; } _startDispatching(payload) { for (var id in this._callbacks) { this._isPending[id] = false; this._isHandled[id] = false; } this._pendingPayload = payload; this._isDispatching = true; } _stopDispatching() { this._pendingPayload = null; this._isDispatching = false; } } ``` Now we are all set to create a dispatcher that is more specific to our app, which we'll call AppDispatcher. ```javascript var Dispatcher = require('./Dispatcher'); var merge = require('react/lib/merge'); var AppDispatcher = merge(Dispatcher.prototype, { /** * A bridge function between the views and the dispatcher, marking the action * as a view action.  Another variant here could be handleServerAction. * @param {object} action The data coming from the view. */ handleViewAction: function(action) { this.dispatch({ source: 'VIEW_ACTION', action: action }); } }); module.exports = AppDispatcher; ``` Now we've created an implementation that is a bit more specific to our needs, with a helper function we can use when we create actions. We might expand on this later to provide a separate helper for server updates, but for now this is all we need. You don't actually need to create an AppDispatcher in every application, but we wanted to show it here as an example.  The creation of the AppDispatcher allows us to extend the functionality of the Dispatcher.  In this application, for example, we have provided metadata about the source of the action outside of the action itself. Creating Stores ---------------- We can use Node's EventEmitter to get started with a store. We need EventEmitter to broadcast the 'change' event to our controller-views. So let's take a look at what that looks like. I've omitted some of the code for the sake of brevity, but for the full version see [TodoStore.js](https://github.com/Facebook/flux/blob/master/examples/flux-todomvc/js/stores/TodoStore.js) in the TodoMVC example code. ```javascript var AppDispatcher = require('../dispatcher/AppDispatcher'); var EventEmitter = require('events').EventEmitter; var TodoConstants = require('../constants/TodoConstants'); var merge = require('react/lib/merge'); var CHANGE_EVENT = 'change'; var _todos = {}; // collection of todo items /** * Create a TODO item. * @param {string} text The content of the TODO */ function create(text) { // Using the current timestamp in place of a real id. var id = Date.now(); _todos[id] = { id: id, complete: false, text: text }; } /** * Delete a TODO item. * @param {string} id */ function destroy(id) { delete _todos[id]; } var TodoStore = merge(EventEmitter.prototype, { /** * Get the entire collection of TODOs. * @return {object} */ getAll: function() { return _todos; }, emitChange: function() { this.emit(CHANGE_EVENT); }, /** * @param {function} callback */ addChangeListener: function(callback) { this.on(CHANGE_EVENT, callback); }, /** * @param {function} callback */ removeChangeListener: function(callback) { this.removeListener(CHANGE_EVENT, callback); }, dispatcherIndex: AppDispatcher.register(function(payload) { var action = payload.action; var text; switch(action.actionType) { case TodoConstants.TODO_CREATE: text = action.text.trim(); if (text !== '') { create(text); TodoStore.emitChange(); } break; case TodoConstants.TODO_DESTROY: destroy(action.id); TodoStore.emitChange(); break; // add more cases for other actionTypes, like TODO_UPDATE, etc. } return true; // No errors. Needed by promise in Dispatcher. }) }); module.exports = TodoStore; ``` There are a few important things to note in the above code. To start, we are maintaining a private data structure called _todos. This object contains all the individual to-do items. Because this variable lives outside the class, but within the closure of the module, it remains private — it cannot be directly changed from the outside. This helps us preserve a distinct input/output interface for the flow of data by making it impossible to update the store without using an action. Another important part is the registration of the store's callback with the dispatcher. We pass in our payload handling callback to the dispatcher and preserve the index that this store has in the dispatcher's registry. The callback function currently only handles two actionTypes, but later we can add as many as we need. Listening to Changes with a Controller-View ------------------------------------------- We need a React component near the top of our component hierarchy to listen for changes in the store. In a larger app, we would have more of these listening components, perhaps one for every section of the page. In Facebook's Ads Creation Tool, we have many of these controller-like views, each governing a specific section of the UI. In the Lookback Video Editor, we only had two: one for the animated preview and one for the image selection interface. Here's one for our TodoMVC example. Again, this is slightly abbreviated, but for the full code you can take a look at the TodoMVC example's [TodoApp.react.js](https://github.com/facebook/flux/blob/master/examples/flux-todomvc/js/components/TodoApp.react.js) ```javascript /** @jsx React.DOM */ var Footer = require('./Footer.react'); var Header = require('./Header.react'); var MainSection = require('./MainSection.react'); var React = require('react'); var TodoStore = require('../stores/TodoStore'); function getTodoState() { return { allTodos: TodoStore.getAll() }; } var TodoApp = React.createClass({ getInitialState: function() { return getTodoState(); }, componentDidMount: function() { TodoStore.addChangeListener(this._onChange); }, componentWillUnmount: function() { TodoStore.removeChangeListener(this._onChange); }, /** * @return {object} */ render: function() { return ( <div> <Header /> <MainSection allTodos={this.state.allTodos} areAllComplete={this.state.areAllComplete} /> <Footer allTodos={this.state.allTodos} /> </div> ); }, _onChange: function() { this.setState(getTodoState()); } }); module.exports = TodoApp; ``` Now we're in our familiar React territory, utilizing React's lifecycle methods. We set up the initial state of this controller-view in getInitialState(), register an event listener in componentDidMount(), and then clean up after ourselves within componentWillUnmount(). We render a containing div and pass down the collection of states we got from the TodoStore. The Header component contains the primary text input for the application, but it does not need to know the state of the store. The MainSection and Footer do need this data, so we pass it down to them. More Views ---------- At a high level, the React component hierarchy of the app looks like this: ```javascript <TodoApp> <Header> <TodoTextInput /> <MainSection> <ul> <TodoItem /> </ul> </MainSection> </Header> </TodoApp> ``` If a TodoItem is in edit mode, it will also render a TodoTextInput as a child. Let's take a look at how some of these components display the data they receive as props, and how they communicate through actions with the dispatcher. The MainSection needs to iterate over the collection of to-do items it received from TodoApp to create the list of TodoItems. In the component's render() method, we can do that iteration like so: ```javascript var allTodos = this.props.allTodos; for (var key in allTodos) { todos.push(<TodoItem key={key} todo={allTodos[key]} />); } return ( <section id="main"> <ul id="todo-list">{todos}</ul> </section> ); ``` Now each TodoItem can display its own text, and perform actions utilizing its own ID. Explaining all the different actions that a TodoItem can invoke in the TodoMVC example goes beyond the scope of this article, but let's just take a look at the action that deletes one of the to-do items. Here is an abbreviated version of the TodoItem: ```javascript /** @jsx React.DOM */ var React = require('react'); var TodoActions = require('../actions/TodoActions'); var TodoTextInput = require('./TodoTextInput.react'); var TodoItem = React.createClass({ propTypes: { todo: React.PropTypes.object.isRequired }, render: function() { var todo = this.props.todo; return ( <li key={todo.id}> <label> {todo.text} </label> <button className="destroy" onClick={this._onDestroyClick} /> </li> ); }, _onDestroyClick: function() { TodoActions.destroy(this.props.todo.id); } }); module.exports = TodoItem; ``` With a destroy action available in our library of TodoActions, and a store ready to handle it, connecting the user's interaction with application state changes could not be simpler. We just wrap our onClick handler around the destroy action, provide it with the id, and we're done. Now the user can click the destroy button and kick off the Flux cycle to update the rest of the application. Text input, on the other hand, is just a bit more complicated because we need to hang on to the state of the text input within the React component itself. Let's take a look at how TodoTextInput works. As you'll see below, with every change to the input, React expects us to update the state of the component. So when we are finally ready to save the text inside the input, we will put the value held in the component's state in the action's payload. This is UI state, rather than application state, and keeping that distinction in mind is a good guide for where state should live. All application state should live in the store, while components occasionally hold on to UI state. Ideally, React components preserve as little state as possible. Because TodoTextInput is being used in multiple places within our application, with different behaviors, we'll need to pass the onSave method in as a prop from the component's parent. This allows onSave to invoke different action creator methods depending on where it is used. ```javascript /** @jsx React.DOM */ var React = require('react'); var ReactPropTypes = React.PropTypes; var ENTER_KEY_CODE = 13; var TodoTextInput = React.createClass({ propTypes: { className: ReactPropTypes.string, id: ReactPropTypes.string, placeholder: ReactPropTypes.string, onSave: ReactPropTypes.func.isRequired, value: ReactPropTypes.string }, getInitialState: function() { return { value: this.props.value || '' }; }, /** * @return {object} */ render: function() /*object*/ { return ( <input className={this.props.className} id={this.props.id} placeholder={this.props.placeholder} onBlur={this._save} onChange={this._onChange} onKeyDown={this._onKeyDown} value={this.state.value} autoFocus={true} /> ); }, /** * Invokes the callback passed in as onSave, allowing this component to be * used in different ways. */ _save: function() { this.props.onSave(this.state.value); this.setState({ value: '' }); }, /** * @param {object} event */ _onChange: function(/*object*/ event) { this.setState({ value: event.target.value }); }, /** * @param {object} event */ _onKeyDown: function(event) { if (event.keyCode === ENTER_KEY_CODE) { this._save(); } } }); module.exports = TodoTextInput; ``` The Header passes in the onSave method as a prop to allow the TodoTextInput to create new to-do items: ```javascript /** @jsx React.DOM */ var React = require('react'); var TodoActions = require('../actions/TodoActions'); var TodoTextInput = require('./TodoTextInput.react'); var Header = React.createClass({ /** * @return {object} */ render: function() { return ( <header id="header"> <h1>todos</h1> <TodoTextInput id="new-todo" placeholder="What needs to be done?" onSave={this._onSave} /> </header> ); }, /** * Event handler called within TodoTextInput. * Defining this here allows TodoTextInput to be used in multiple places * in different ways. * @param {string} text */ _onSave: function(text) { TodoActions.create(text); } }); module.exports = Header; ``` In a different context, such as in editing mode for an existing to-do item, we might pass an onSave callback that invokes `TodoActions.update(text)` instead. Creating Actions with Semantic Methods -------------------------------------- Here is the basic code for the two action creator methods we used above in our views: ```javascript /** * TodoActions */ var AppDispatcher = require('../dispatcher/AppDispatcher'); var TodoConstants = require('../constants/TodoConstants'); var TodoActions = { /** * @param {string} text */ create: function(text) { AppDispatcher.handleViewAction({ actionType: TodoConstants.TODO_CREATE, text: text }); }, /** * @param {string} id */ destroy: function(id) { AppDispatcher.handleViewAction({ actionType: TodoConstants.TODO_DESTROY, id: id }); }, }; module.exports = TodoActions; ``` As you can see, we really would not need to have the helpers AppDispatcher.handleViewAction() or TodoActions.create(). We could, in theory, call AppDispatcher.dispatch() directly and provide a payload. But as our application grows, having these helpers keeps the code clean and semantic. It's just a lot cleaner to write TodoActions.destroy(id) instead of writing a whole lot of things that our TodoItem shouldn't have to know about. The payload produced by the TodoActions.create() will look like: ```javascript { source: 'VIEW_ACTION', action: { type: 'TODO_CREATE', text: 'Write blog post about Flux' } } ``` This payload is provided to the TodoStore through its registered callback. The TodoStore then broadcasts the 'change' event, and the MainSection responds by fetching the new collection of to-do items from the TodoStore and changing its state. This change in state causes the TodoApp component to call its own render() method, and the render() method of all of its descendents. Start Me Up ----------- The bootstrap file of our application is app.js. It simply takes the TodoApp component and renders it in the root element of the application. ```javascript /** @jsx React.DOM */ var React = require('react'); var TodoApp = require('./components/TodoApp.react'); React.renderComponent( <TodoApp />, document.getElementById('todoapp') ); ``` Dependency Management in the Dispatcher ---------------------------------------------- As our application grows beyond this simple application to contain multiple stores, we'll need a way to be able to manage dependencies between them. That is, Store A might need to derive data based on Store B's data, so Store A would need Store B to update itself first.  This functionality is available with the Dispatcher's waitFor() method. We would call waitFor() within the store's registered callback like so: ```javascript Dispatcher.waitFor([StoreB.dispatcherIndex, StoreC.dispatcherIndex]); // now do things, knowing that both StoreB and StoreC have updated ``` In the source code, you can see that we are interupting the synchronous iteration over the callbacks and starting a new iteration of callbacks based on the array of dispatcherIndexes passed into waitFor(). ```javascript /** * Waits for the callbacks specified to be invoked before continuing execution * of the current callback. This method should only be used by a callback in * response to a dispatched payload. * * @param {array<string>} ids */ waitFor(ids) { invariant( this._isDispatching, 'Dispatcher.waitFor(...): Must be invoked while dispatching.' ); for (var ii = 0; ii < ids.length; ii++) { var id = ids[ii]; if (this._isPending[id]) { invariant( this._isHandled[id], 'Dispatcher.waitFor(...): Circular dependency detected while ' + 'waiting for `%s`.', id ); continue; } invariant( this._callbacks[id], 'Dispatcher.waitFor(...): `%s` does not map to a registered callback.', id ); this._invokeCallback(id); } } ``` Now within the store's callback we can explicitly wait for any dependencies to first update before moving forward.  However, if Store A waits for Store B, and B waits for A, then a circular dependency will occur. To help prevent this situation, the dispatcher will throw an error in the browser console if we accidentally have two stores that are waiting for each other. The Future of Flux ------------------ A lot of people ask if Facebook will release Flux as an open source framework. Really, Flux is just an architecture, not a framework.  But perhaps a Flux boilerplate project might make sense, if there is enough interest. Please let us know if you'd like to see us do this. Thanks for taking the time to read about how we build client-side applications at Facebook. We hope Flux proves as useful to you as it has to us. </del> <ins> This page has been moved to the Flux website. [View it there](http://facebook.github.io/flux/docs/todo-list.html). </ins>


* `Object.create` – Provided by `es5-sham.js` from [kriskowal's es5-shim](https://github.com/kriskowal/es5-shim). * `console.*` – Only needed when using the unminified build. If you need to polyfill this, try [paulmillr's console-polyfill](https://github.com/paulmillr/console-polyfill). <ins> ### Cross-browser Issues Although React is pretty good at abstracting browser differences, some browsers are limited or present quirky behaviors that we couldn't find a workaround. #### onScroll event on IE8 On IE8 the `onScroll` event doesn't bubbles and IE8 doesn't have an API to define handlers to the capturing phase of an event, meaning there is no way for React to listen to these events. Currently a handler to this event is ignored on IE8. See the [onScroll doesn't work in IE8](https://github.com/facebook/react/issues/631) GitHub issue for more information. </ins>


<div className="content" dangerouslySetInnerHTML={{  __html: converter.makeHtml(this.state.value)   __html: marked(this.state.value, {sanitize: true})  }} />


listeners: null, onChange: _handleChange.bind(inst), }; <ins> if (__DEV__) { inst._wrapperState.controlled = props.checked !== undefined || props.value !== undefined; } </ins> }, updateWrapper: function(inst) {


): void { if (__DEV__) { currentHookNameInDev = 'useImperativeHandle'; <ins> warning( typeof create === 'function', 'Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: %s.', create !== null ? typeof create : 'null', ); </ins> } // TODO: If deps are provided, should we skip comparing the ref itself? const nextDeps =


}); ``` <del> This is a special API that intentionally makes it difficult to insert raw HTML, but for Showdown we'll take advantage of this backdoor. </del> <ins> This is a special API that intentionally makes it difficult to insert raw HTML, but for marked we'll take advantage of this backdoor. </ins> <del> **Remember:** by using this feature you're relying on Showdown to be secure. </del> <ins> **Remember:** by using this feature you're relying on marked to be secure. In this case, we pass `sanitize: true` which tells marked to escape any HTML markup in the source instead of passing it through unchanged. </ins> ### Hook up the data model


} } <ins> function shouldConstruct(Component) { return Component.prototype && Component.prototype.isReactComponent; } </ins> /** * ------------------ The Life-Cycle of a Composite Component ------------------ *


); } <ins> function optionPostMount() { var inst = this; ReactDOMOption.postMountWrapper(inst); } </ins> // There are so many media events, it makes sense to just // maintain a list rather than create a `trapBubbledEvent` for each var mediaEvents = {


var ReactServerRendering; var ReactTestUtils; <del> var cx; </del> var reactComponentExpect; var mocks; describe('ReactCompositeComponent', function() { beforeEach(function() { <del> cx = require('cx'); </del> mocks = require('mocks'); reactComponentExpect = require('reactComponentExpect');


var didWarnValueNull = false; var didWarnValueDefaultValue = false; var didWarnCheckedDefaultChecked = false; <ins> var didWarnControlledToUncontrolled = false; var didWarnUncontrolledToControlled = false; </ins> function forceUpdateIfMounted() { if (this._rootNodeID) {


 const React = window.React; import Fixture from '../../Fixture'; class NumberInputDecimal extends React.Component { state = { value: '.98' }; changeValue = () => { this.setState({ value: '0.98', }); } render() { const {value} = this.state; return ( <Fixture>
{this.props.children}

 <input type="number" value={value} onChange={(e) => { this.setState({value: e.target.value}); }} /> <button onClick={this.changeValue}>change.98 to 0.98</button>
 </Fixture> ); } } export default NumberInputDecimal;


*/ import throttle from 'lodash.throttle'; <del> import { useCallback, useEffect, useLayoutEffect, useMemo, useState, } from 'react'; </del> <ins> import {useCallback, useEffect, useLayoutEffect, useState} from 'react'; </ins> import {unstable_batchedUpdates as batchedUpdates} from 'react-dom'; import { localStorageGetItem,


assign( ShallowComponentWrapper.prototype, ReactCompositeComponent.Mixin, { <ins> _constructComponent: ReactCompositeComponent.Mixin._constructComponentWithoutOwner, </ins> _instantiateReactComponent: function(element) { return new NoopInternalComponent(element); },


hookSourceData.originalSourceAST = sourceMetadata.originalSourceAST; hookSourceData.originalSourceCode = sourceMetadata.originalSourceCode; } else { <ins> // TypeScript is the most commonly used typed JS variant so let's default to it // unless we detect explicit Flow usage via the "@flow" pragma. const plugin = originalSourceCode.indexOf('@flow') > 0 ? 'flow' : 'typescript'; </ins> // TODO (named hooks) Parsing should ideally be done off of the main thread. const originalSourceAST = parse(originalSourceCode, { sourceType: 'unambiguous', <del> plugins: ['jsx', 'typescript'], </del> <ins> plugins: ['jsx', plugin], </ins> }); hookSourceData.originalSourceAST = originalSourceAST; if (__DEBUG__) {


if (__DEV__) { warnIfValueIsNull(props); <ins> var initialValue = inst._wrapperState.initialChecked || inst._wrapperState.initialValue; var defaultValue = props.defaultChecked || props.defaultValue; var controlled = props.checked !== undefined || props.value !== undefined; var owner = inst._currentElement._owner; if ( (initialValue || !inst._wrapperState.controlled) && controlled && !didWarnUncontrolledToControlled ) { warning( false, '%s is changing a uncontrolled input of type %s to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type ); didWarnUncontrolledToControlled = true; } if ( inst._wrapperState.controlled && (defaultValue || !controlled) && !didWarnControlledToUncontrolled ) { warning( false, '%s is changing a controlled input of type %s to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components', owner && owner.getName() || 'A component', props.type ); didWarnControlledToUncontrolled = true; } </ins> } // TODO: Shouldn't this be getChecked(props)?


return this.refs.anch; }, render: function() {  var className = cx({'anchorClass': this.props.anchorClassOn});   var className = this.props.anchorClassOn ? 'anchorClass' : '';  return this.props.renderAnchor ?  : ;


} effect = effect.nextEffect; } while (effect !== null); <ins> if (__DEV__) { resetCurrentFiber(); } </ins> isRendering = previousIsRendering;


"node": ">=0.10.0" }, "peerDependencies": { <del> "envify": "~1.0.1" </del> <ins> "envify": "~1.2.0" </ins> }, "browserify": { "transform": ["envify"]


<ins> name: DevTools Check for bug repro on: issues: types: [opened, edited] issue_comment: types: [created, edited] jobs: check-repro: runs-on: ubuntu-latest steps: - uses: actions/github-script@v3 with: github-token: ${{ secrets.GITHUB_TOKEN }} script: | const URL_REGEXP = /### Website or app[rn]+([^#]+)###/m; const REPRO_STEPS_REGEXP = /### Repro steps[rn]+([^#]+)###/m; const LABEL_NEEDS_MORE_INFORMATION = "Resolution: Needs More Information"; const LABEL_UNCONFIRMED = "Status: Unconfirmed"; function debug(...args) { core.info(args.map(JSON.stringify).join(' ')); } if (context.payload.comment) { debug('Ignoring comment update.'); return; } const user = context.payload.sender.login; const issue = context.payload.issue; const body = issue.body; const urlMatch = body.match(URL_REGEXP); const reproStepsMatch = body.match(REPRO_STEPS_REGEXP); const url = urlMatch !== null ? urlMatch[1].trim() : null; const reproSteps = reproStepsMatch !== null ? reproStepsMatch[1].trim() : null; if (!url || !reproSteps) { debug('This issue is not a DevTools bug report.'); return; } debug(`found URL "${url}"`); debug(`found repro steps "${reproSteps}"`); function formatComment(comment) { return comment .split("n") .map((line) => line.trim()) .join("n") .trim(); } async function getGitHubActionComments() { debug(`Loading existing comments...`); const comments = await github.issues.listComments({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, }); return comments.data.filter(comment => { debug(`comment by user: "${comment.user.login}"`); return comment.user.login === 'github-actions[bot]'; }); } async function getIssueLabels() { const issues = await github.issues.listLabelsOnIssue({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, }); return issues.data; } async function closeWithComment(comment) { if (issue.state !== 'open') { debug(`Issue is not open`); return; } const labels = await getIssueLabels(); const label = labels.find(label => label.name === LABEL_UNCONFIRMED); if (!label) { debug(`Issue was not opened via DevTools bug report template`); return; } const comments = await getGitHubActionComments(); if (comments.length > 0) { debug(`Already commented on issue; won't comment again`); return; } debug(`Missing required information`); await github.issues.addLabels({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, labels: [LABEL_NEEDS_MORE_INFORMATION], }); await github.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: formatComment(comment), }); await github.issues.update({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, state: 'closed', }); } async function openWithComment(comment) { if (issue.state !== 'closed') { debug(`Issue is already open`); return; } const labels = await getIssueLabels(); const label = labels.find(label => label.name === LABEL_NEEDS_MORE_INFORMATION); if (!label) { debug(`Issue was not tagged as needs information`); return; } const comments = await getGitHubActionComments(); if (comments.length === 0) { debug(`Issue was closed by someone else; won't reopen`); return; } debug(`Re-opening closed issue`); await github.issues.removeLabel({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, name: LABEL_NEEDS_MORE_INFORMATION, }); await github.issues.createComment({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, body: formatComment(comment), }); await github.issues.update({ issue_number: context.issue.number, owner: context.repo.owner, repo: context.repo.repo, state: 'open', }); } const PROBABLY_NOT_A_URL_REGEX = /(^Chrome$|^Firefox$| Website)/i; const COMMENT_HEADER = ` @${user}: We're sorry you've seen this error. ❤ `.trim(); const COMMENT_FOOTER = ` Please help us by providing a link to a CodeSandbox (https://codesandbox.io/s/new), a repository on GitHub, or a minimal code example that reproduces the problem. (Screenshots or videos can also be helpful if they help provide context on how to repro the bug.) Here are some tips for providing a minimal example: https://stackoverflow.com/help/mcve Issues without repros are automatically closed but we will re-open if you update with repro info. `.trim(); if (url.includes("/localhost")) { closeWithComment(` ${COMMENT_HEADER} Unfortunately the URL you provided ("localhost") is not publicly accessible. (This means that we will not be able to reproduce the problem you're reporting.) ${COMMENT_FOOTER} `); } else if (url.length < 10 || url.match(PROBABLY_NOT_A_URL_REGEX)) { closeWithComment(` ${COMMENT_HEADER} It looks like you forgot to specify a valid URL. (This means that we will not be able to reproduce the problem you're reporting.) ${COMMENT_FOOTER} `); } else if (reproSteps.length < 25) { closeWithComment(` ${COMMENT_HEADER} Unfortunately, it doesn't look like this issue has enough info for one of us to reproduce and fix it though. ${COMMENT_FOOTER} `); } else { openWithComment(` Thank you for providing repro steps! Re-opening issue now for triage. `); } </ins>


form: MUST_USE_ATTRIBUTE, formNoValidate: HAS_BOOLEAN_VALUE, frameBorder: MUST_USE_ATTRIBUTE, <ins> headers: null, </ins> height: MUST_USE_ATTRIBUTE, hidden: MUST_USE_ATTRIBUTE | HAS_BOOLEAN_VALUE, href: null,


override: - ./scripts/circleci/test_entry_point.sh: parallel: true <del> deployment: staging: branch: /.*/ commands: - ./scripts/circleci/upload_build.sh </del>


workInProgress: Fiber, priorityLevel: PriorityLevel, ): void { <ins> if (__DEV__) { checkClassInstance(workInProgress); } </ins> const instance = workInProgress.stateNode; const state = instance.state || null;


<ins> --- layout: none --- <?xml version="1.0" encoding="UTF-8"?> <rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom"> <channel> <title>{{ site.name }}</title> <description>{{ site.description }}</description> <link>{{ site.url }}{{ site.baseurl }}</link> <atom:link href="{{ site.url }}{{ site.baseurl }}/feed.xml" rel="self" type="application/rss+xml" /> {% for post in site.posts limit:10 %} <item> <title>{{ post.title | xml_escape }}</title> <description>{{ post.content | xml_escape }}</description> <pubDate>{{ post.date | date_to_xmlschema }}</pubDate> <link>{{ site.url }}{{ site.baseurl }}{{ post.url }}</link> <guid isPermaLink="true">{{ site.url }}{{ site.baseurl }}{{ post.url }}</guid> </item> {% endfor %} </channel> </rss> </ins>


export function createCache(invalidator: () => mixed): Cache { const resourceMap: ResourceMap = new Map(); <del> function accessRecord<K, V>(resourceType: any, key: K): Record<V> { </del> <ins> function accessRecord<K, V>(resourceType: any, key: K): Record<K, V> { </ins> if (__DEV__) { warning( typeof resourceType !== 'string' && typeof resourceType !== 'number',


* @param [string ...]  Variable list of classNames in the string case. * @return string       Renderable space-separated CSS className. */ <ins> 'use strict'; var warning = require('warning'); var warned = false; </ins> function cx(classNames) { <ins> if (__DEV__) { warning( warned, 'React.addons.classSet will be deprecated in a future version. See ' + 'http://fb.me/react-addons-classset' ); warned = true; } </ins> if (typeof classNames == 'object') { return Object.keys(classNames).filter(function(className) { return classNames[className];


); }); <ins> it('should not enumerate enumerable numbers (#4776)', function() { /*eslint-disable no-extend-native */ Number.prototype['@@iterator'] = function() { throw new Error('number iterator called'); }; /*eslint-enable no-extend-native */ try { var instance = ( <div> {5} {12} {13} </div> ); var traverseFn = jasmine.createSpy(); traverseAllChildren(instance.props.children, traverseFn, null); expect(traverseFn.calls.length).toBe(3); expect(traverseFn).toHaveBeenCalledWith( null, 5, '.0' ); expect(traverseFn).toHaveBeenCalledWith( null, 12, '.1' ); expect(traverseFn).toHaveBeenCalledWith( null, 13, '.2' ); } finally { delete Number.prototype['@@iterator']; } }); </ins> });


 /** * Copyright 2013-2015, Facebook, Inc. * All rights reserved. * * This source code is licensed under the BSD-style license found in the * LICENSE file in the root directory of this source tree. An additional grant * of patent rights can be found in the PATENTS file in the same directory. * * @emails react-core */ 'use strict'; var React; var ReactDOM; var ReactTestUtils; describe('ReactEventIndependence', function() { beforeEach(function() { require('mock-modules').dumpCache(); React = require('React'); ReactDOM = require('ReactDOM'); ReactTestUtils = require('ReactTestUtils'); }); it('does not crash with other react inside', function() { var clicks = 0; var div = ReactTestUtils.renderIntoDocument(
 clicks++} dangerouslySetInnerHTML={{ __html: '<button data-reactid=".z">click me
', }} /> ); ReactTestUtils.SimulateNative.click(div.firstChild); expect(clicks).toBe(1); }); it('does not crash with other react outside', function() { var clicks = 0; var outer = document.createElement('div'); outer.setAttribute('data-reactid', '.z'); var inner = ReactDOM.render( <button onClick={() => clicks++}>click me</button>, outer ); ReactTestUtils.SimulateNative.click(inner); expect(clicks).toBe(1); }); it('does not when event fired on unmounted tree', function() { var clicks = 0; var container = document.createElement('div'); var button = ReactDOM.render( <button onClick={() => clicks++}>click me</button>, container ); // Now we unmount the component, as if caused by a non-React event handler // for the same click we're about to simulate, like closing a layer: ReactDOM.unmountComponentAtNode(container); ReactTestUtils.SimulateNative.click(button); // Since the tree is unmounted, we don't dispatch the click event. expect(clicks).toBe(0); }); });


describe('ReactDOMComponent', function() { var React; var ReactDOM; <del> var ReactDOMFeatureFlags; </del> var ReactDOMServer; beforeEach(function() { jest.resetModuleRegistry(); React = require('React'); <del> ReactDOMFeatureFlags = require('ReactDOMFeatureFlags') </del> ReactDOM = require('ReactDOM'); ReactDOMServer = require('ReactDOMServer'); });


- Gemfile.lock - README.md - Rakefile <ins> url: http://facebook.github.io </ins> baseurl: /react permalink: /blog/:year/:month/:day/:title.html


expect(console.error.argsForCall.length).toBe(1); }); <ins> it('should warn if controlled input switches to uncontrolled', function() { var stub = <input type="text" value="controlled" onChange={emptyFunction} />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="text" />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a controlled input of type text to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if controlled input switches to uncontrolled with defaultValue', function() { var stub = <input type="text" value="controlled" onChange={emptyFunction} />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="text" defaultValue="uncontrolled" />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a controlled input of type text to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if uncontrolled input switches to controlled', function() { var stub = <input type="text" />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="text" value="controlled" />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a uncontrolled input of type text to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if controlled checkbox switches to uncontrolled', function() { var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="checkbox" />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a controlled input of type checkbox to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if controlled checkbox switches to uncontrolled with defaultChecked', function() { var stub = <input type="checkbox" checked={true} onChange={emptyFunction} />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="checkbox" defaultChecked={true} />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a controlled input of type checkbox to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if uncontrolled checkbox switches to controlled', function() { var stub = <input type="checkbox" />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="checkbox" checked={true} />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a uncontrolled input of type checkbox to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if controlled radio switches to uncontrolled', function() { var stub = <input type="radio" checked={true} onChange={emptyFunction} />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="radio" />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a controlled input of type radio to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if controlled radio switches to uncontrolled with defaultChecked', function() { var stub = <input type="radio" checked={true} onChange={emptyFunction} />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="radio" defaultChecked={true} />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a controlled input of type radio to be uncontrolled. ' + 'Input elements should not switch from controlled to uncontrolled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); it('should warn if uncontrolled radio switches to controlled', function() { var stub = <input type="radio" />; var container = document.createElement('div'); ReactDOM.render(stub, container); ReactDOM.render(<input type="radio" checked={true} />, container); expect(console.error.argsForCall.length).toBe(1); expect(console.error.argsForCall[0][0]).toContain( 'A component is changing a uncontrolled input of type radio to be controlled. ' + 'Input elements should not switch from uncontrolled to controlled (or viceversa). ' + 'Decide between using a controlled or uncontrolled input ' + 'element for the lifetime of the component. More info: https://fb.me/react-controlled-components' ); }); </ins> it('sets type before value always', function() { var log = []; var originalCreateElement = document.createElement;


const [parsedValue, setParsedValue] = useState(initialValue); const [isValid, setIsValid] = useState(initialIsValid); <del> const reset = useCallback(() => { setEditableValue(smartStringify(initialValue)); setParsedValue(initialValue); setIsValid(initialIsValid); }, []); </del> <ins> const reset = useCallback( () => { setEditableValue(smartStringify(initialValue)); setParsedValue(initialValue); setIsValid(initialIsValid); }, [initialValue, initialIsValid], ); </ins> const update = useCallback(newValue => { let isNewValueValid = false;


disableInputAttributeSyncing, enableTrustedTypesIntegration, deferPassiveEffectCleanupDuringUnmount, <ins> warnAboutShorthandPropertyCollision, </ins> } = require('ReactFeatureFlags'); // In www, we have experimental support for gathering data


// TODO: we should warn here. }); }); <ins> describe('checked inputs without a value property', function() { // In absence of a value, radio and checkboxes report a value of "on". // Between 16 and 16.2, we assigned a node's value to it's current // value in order to "dettach" it from defaultValue. This had the unfortunate // side-effect of assigning value="on" to radio and checkboxes it('does not add "on" in absence of value on a checkbox', function() { const container = document.createElement('div'); ReactDOM.render( <input type="checkbox" defaultChecked={true} />, container, ); const node = container.firstChild; expect(node.value).toBe('on'); expect(node.hasAttribute('value')).toBe(false); }); it('does not add "on" in absence of value on a radio', function() { const container = document.createElement('div'); ReactDOM.render(<input type="radio" defaultChecked={true} />, container); const node = container.firstChild; expect(node.value).toBe('on'); expect(node.hasAttribute('value')).toBe(false); }); }); </ins> });


"benchmark": "~1.0.0", "browserify": "~3.20.0", "coverify": "~1.0.4", <del> "envify": "~1.0.1", </del> <ins> "envify": "~1.2.0", </ins> "es3ify": "~0.1.2", "es5-shim": "~2.3.0", "grunt": "~0.4.2",


charSet: null, challenge: null, checked: MUST_USE_PROPERTY | HAS_BOOLEAN_VALUE, <ins> cite: null, </ins> classID: null, className: null, cols: HAS_POSITIVE_NUMERIC_VALUE,


A Component Using External Plugins

 React is flexible and provides hooks that allow you to interface with  other libraries and frameworks. This example uses Showdown, an external   other libraries and frameworks. This example uses **marked**, an external  Markdown library, to convert the textarea's value in real-time.


export const disableJavaScriptURLs = false; export const disableInputAttributeSyncing = false; export const exposeConcurrentModeAPIs = __EXPERIMENTAL__; <del> export const warnAboutShorthandPropertyCollision = false; </del> <ins> export const warnAboutShorthandPropertyCollision = true; </ins> export const enableSchedulerDebugging = false; export const enableDeprecatedFlareAPI = false; export const enableFundamentalAPI = false;


expect(console.error.argsForCall.length).toBe(0); }); <ins> it('should not enumerate enumerable numbers (#4776)', function() { /*eslint-disable no-extend-native */ Number.prototype['@@iterator'] = function() { throw new Error('number iterator called'); }; /*eslint-enable no-extend-native */ try { void ( <div> {5} {12} {13} </div> ); } finally { delete Number.prototype['@@iterator']; } }); </ins> });


]); }); <ins> it('warns for bad useImperativeHandle first arg', () => { const {useImperativeHandle} = React; function App() { useImperativeHandle({ focus() {}, }); return null; } expect(() => { expect(() => { ReactTestRenderer.create(<App />); }).toThrow('create is not a function'); }).toWarnDev([ 'Expected useImperativeHandle() first argument to either be a ' + 'ref callback or React.createRef() object. ' + 'Instead received: an object with keys {focus}.', 'Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: undefined.', ]); }); it('warns for bad useImperativeHandle second arg', () => { const {useImperativeHandle} = React; const App = React.forwardRef((props, ref) => { useImperativeHandle(ref, { focus() {}, }); return null; }); expect(() => { ReactTestRenderer.create(<App />); }).toWarnDev([ 'Expected useImperativeHandle() second argument to be a function ' + 'that creates a handle. Instead received: object.', ]); }); </ins> // https://github.com/facebook/react/issues/14022 it('works with ReactDOMServer calls inside a component', () => { const {useState} = React;


<meta property="og:description" content="A JavaScript library for building user interfaces" /> <link rel="shortcut icon" href="/react/favicon.ico"> <ins> <link rel="alternate" type="application/rss+xml" title="{{ site.name }}" href="{{ site.url }}{{ site.baseurl }}/feed.xml"> </ins> <link rel="stylesheet" href="/react/css/react.css"> <link rel="stylesheet" href="/react/css/syntax.css">


inst._wrapperState = {selected: selected}; }, <ins> postMountWrapper: function(inst) { // value="" should make a value attribute (#6219) var props = inst._currentElement.props; if (props.value != null) { var node = ReactDOMComponentTree.getNodeFromInstance(inst); node.setAttribute('value', props.value); } }, </ins> getNativeProps: function(inst, props) { var nativeProps = Object.assign({selected: undefined, children: undefined}, props);


module Jekyll module SidebarItemFilter def sidebar_item_link(item) pageID = @context.registers[:page]["id"] itemID = item["id"] href = item["href"] || "/react/docs/#{itemID}.html" className = pageID == itemID ? ' class="active"' : '' return "#{item["title"]}" end end end Liquid::Template.register_filter(Jekyll::SidebarItemFilter)


miss: A => Promise<V>, missArg: A, ): void { <del> const record: Record<V> = accessRecord(resourceType, key); </del> <ins> const record: Record<K, V> = accessRecord(resourceType, key); </ins> switch (record.status) { case Empty: // Warm the cache.


// Control this behavior with a flag to support 16.6 minor releases in the meanwhile. export const exposeConcurrentModeAPIs = __EXPERIMENTAL__; <del> export const warnAboutShorthandPropertyCollision = false; </del> <ins> export const warnAboutShorthandPropertyCollision = true; </ins> // Experimental React Flare event system and event components support. export const enableDeprecatedFlareAPI = false;


<script src="https://fb.me/react-{{site.react_version}}.js"></script> <script src="https://fb.me/JSXTransformer-{{site.react_version}}.js"></script> <script src="https://code.jquery.com/jquery-1.10.0.min.js"></script> <del> <script src="https://cdnjs.cloudflare.com/ajax/libs/showdown/0.3.1/showdown.min.js"></script> </del> <ins> <script src="https://cdnjs.cloudflare.com/ajax/libs/marked/0.3.2/marked.min.js"></script> </ins> </head> ``` Next, let's convert the comment text to Markdown and output it: <del> ```javascript{2,10} </del> <ins> ```javascript{9} </ins> // tutorial6.js <del> var converter = new Showdown.converter(); </del> var Comment = React.createClass({ render: function() { return (


export const replayFailedUnitOfWorkWithInvokeGuardedCallback = false; export const warnAboutDeprecatedLifecycles = true; <del> export const warnAboutShorthandPropertyCollision = false; </del> export const disableLegacyContext = false; export const warnAboutStringRefs = false; export const warnAboutDefaultPropsOnFunctionComponents = false;


expect(store).toMatchSnapshot('2: add host nodes'); }); <ins> // This test is not the same cause as what's reported on GitHub, // but the resulting behavior (owner mounting after descendant) is the same. // Thec ase below is admittedly contrived and relies on side effects. // I'mnot yet sure of how to reduce the GitHub reported production case to a test though. // See https://github.com/facebook/react/issues/21445 it('should handle when a component mounts before its owner', () => { const promise = new Promise(resolve => {}); let Dynamic = null; const Owner = () => { Dynamic = <Child />; throw promise; }; const Parent = () => { return Dynamic; }; const Child = () => null; const container = document.createElement('div'); act(() => ReactDOM.render( <> <React.Suspense fallback="Loading..."> <Owner /> </React.Suspense> <Parent /> </>, container, ), ); expect(store).toMatchInlineSnapshot(` [root] <Suspense> ▾ <Parent> <Child> `); }); </ins> describe('collapseNodesByDefault:false', () => { beforeEach(() => { store.collapseNodesByDefault = false;


var MARKDOWN_COMPONENT = ` <del> var converter = new Showdown.converter(); </del> var MarkdownEditor = React.createClass({ getInitialState: function() { return {value: 'Type some *markdown* here!'};