From: Daniel Kinzler Date: Mon, 5 Mar 2012 11:53:21 +0000 (+0000) Subject: integration with Title and Revision (work in progress) X-Git-Tag: 1.31.0-rc.0~22097^2^2~302 X-Git-Url: http://git.cyclocoop.org/%7B%24www_url%7Dadmin/compta/exercices/?a=commitdiff_plain;h=8ede0ad20e50fb45f1b8024a0e9b15b015791f68;p=lhc%2Fweb%2Fwiklou.git integration with Title and Revision (work in progress) --- diff --git a/includes/Article.php b/includes/Article.php index 1fbcdb4ce8..06c460d78f 100644 --- a/includes/Article.php +++ b/includes/Article.php @@ -37,7 +37,7 @@ class Article extends Page { */ public $mParserOptions; - var $mContent; // !< + var $mContent; // !< #FIXME: use Content object! var $mContentLoaded = false; // !< var $mOldId; // !< @@ -557,6 +557,7 @@ class Article extends Page { # Pages containing custom CSS or JavaScript get special treatment if ( $this->getTitle()->isCssOrJsPage() || $this->getTitle()->isCssJsSubpage() ) { + #FIXME: use Content object instead! wfDebug( __METHOD__ . ": showing CSS/JS source\n" ); $this->showCssOrJsPage(); $outputDone = true; @@ -694,17 +695,18 @@ class Article extends Page { * This is hooked by SyntaxHighlight_GeSHi to do syntax highlighting of these * page views. */ - protected function showCssOrJsPage() { + protected function showCssOrJsPage() { #FIXME: deprecate, keep for BC global $wgOut; $dir = $this->getContext()->getLanguage()->getDir(); $lang = $this->getContext()->getLanguage()->getCode(); $wgOut->wrapWikiMsg( "
\n$1\n
", - 'clearyourcache' ); + 'clearyourcache' ); #FIXME: get this from handler // Give hooks a chance to customise the output if ( wfRunHooks( 'ShowRawCssJs', array( $this->mContent, $this->getTitle(), $wgOut ) ) ) { + #FIXME: use content object instead // Wrap the whole lot in a
 and don't parse
 			$m = array();
 			preg_match( '!\.(css|js)$!u', $this->getTitle()->getText(), $m );
diff --git a/includes/Content.php b/includes/Content.php
new file mode 100644
index 0000000000..b8e138e7b8
--- /dev/null
+++ b/includes/Content.php
@@ -0,0 +1,166 @@
+mModelName = $modelName;
+        $this->mTitle = $title;
+        $this->mRevId = $revId;
+    }
+
+    public function getModelName() {
+        return $this->mModelName;
+    }
+
+    public function getTitle() {
+        return $this->mTitle;
+    }
+
+    public function getRevId() {
+        return $this->mRevId;
+    }
+
+    public abstract function getSearchText( $obj );
+
+    public abstract function getWikitextForTransclusion( $obj );
+
+    public abstract function getParserOutput( ParserOptions $options = NULL );
+
+    public abstract function getRawData( );
+
+    public function getHtml( ParserOptions $options ) {
+        $po = $this->getParserOutput( $options );
+        return $po->getText();
+    }
+
+    public function getIndexUpdateJobs( ParserOptions $options , $recursive = true ) {
+        $po = $this->getParserOutput( $options );
+        $update = new LinksUpdate( $this->mTitle, $po, $recursive );
+        return $update;
+    }
+
+    #XXX: is the native model for wikitext a string or the parser output? parse early or parse late?
+}
+
+class TextContent extends Content {
+    public function __construct( $text, Title $title, $revId, $modelName ) {
+        parent::__construct($title, $revId, $modelName);
+
+        $this->mText = $text;
+    }
+
+    public function getSearchText( $obj ) {
+        return $this->getRawData();
+    }
+
+    public function getWikitextForTransclusion( $obj ) {
+        return $this->getRawData();
+    }
+
+
+    public function getParserOutput( ParserOptions $options = null ) {
+        # generic implementation, relying on $this->getHtml()
+
+        $html = $this->getHtml( $options );
+        $po = new ParserOutput( $html );
+
+        #TODO: cache settings, etc?
+
+        return $po;
+    }
+
+    public function getHtml( ParserOptions $options ) {
+        $html = "";
+        $html .= "
\n";
+        $html .= htmlspecialchars( $this->getRawData() );
+        $html .= "\n
\n"; + + return $html; + } + + + public function getRawData( ) { + global $wgParser, $wgUser; + + $text = $this->mText; + return $text; + } + +} + +class WikitextContent extends TextContent { + public function __construct( $text, Title $title, $revId = null) { + parent::__construct($text, $title, $revId, CONTENT_MODEL_WIKITEXT); + + $this->mDefaultParserOptions = null; + } + + public function getDefaultParserOptions() { + global $wgUser, $wgContLang; + + if ( !$this->mDefaultParserOptions ) { + #TODO: use static member?! + $this->mDefaultParserOptions = ParserOptions::newFromUserAndLang( $wgUser, $wgContLang ); + } + + return $this->mDefaultParserOptions; + } + + public function getParserOutput( ParserOptions $options = null ) { + global $wgParser; + + #TODO: quick local cache: if $options is NULL, use ->mParserOutput! + #FIXME: need setParserOutput, so we can use stuff from the parser cache?? + #FIXME: ...or we somehow need to know the parser cache key?? + + if ( !$options ) { + $options = $this->getDefaultParserOptions(); + } + + $po = $wgParser->parse( $this->mText, $this->getTitle(), $options ); + + return $po; + } + +} + + +class JavaScriptContent extends TextContent { + public function __construct( $text, Title $title, $revId = null ) { + parent::__construct($text, $title, $revId, CONTENT_MODEL_JAVASCRIPT); + } + + public function getHtml( ParserOptions $options ) { + $html = ""; + $html .= "
\n";
+        $html .= htmlspecialchars( $this->getRawData() );
+        $html .= "\n
\n"; + + return $html; + } + +} + +class CssContent extends TextContent { + public function __construct( $text, Title $title, $revId = null ) { + parent::__construct($text, $title, $revId, CONTENT_MODEL_CSS); + } + + public function getHtml( ParserOptions $options ) { + $html = ""; + $html .= "
\n";
+        $html .= htmlspecialchars( $this->getRawData() );
+        $html .= "\n
\n"; + + return $html; + } +} + +#TODO: MultipartMultipart < WikipageContent (Main + Links + X) +#TODO: LinksContent < LanguageLinksContent, CategoriesContent +#EXAMPLE: CoordinatesContent +#EXAMPLE: WikidataContent diff --git a/includes/ContentHandler.php b/includes/ContentHandler.php index 7b076de647..b7761d63af 100644 --- a/includes/ContentHandler.php +++ b/includes/ContentHandler.php @@ -12,7 +12,90 @@ * */ abstract class ContentHandler { - + + public static function getDefaultModelFor( Title $title ) { + global $wgNamespaceContentModels; + + # NOTE: this method must not rely on $title->getContentModelName() directly or indirectly, + # because it is used to initialized the mContentModelName memebr. + + $ns = $title->getNamespace(); + + $ext = false; + $m = null; + $model = null; + + if ( !empty( $wgNamespaceContentModels[ $ns ] ) ) { + $model = $wgNamespaceContentModels[ $ns ]; + } + + # hook can determin default model + if ( !wfRunHooks( 'DefaultModelFor', array( $title, &$model ) ) ) { #FIXME: document new hook! + if ( $model ) return $model; + } + + # Could this page contain custom CSS or JavaScript, based on the title? + $isCssOrJsPage = ( NS_MEDIAWIKI == $ns && preg_match( "!\.(css|js)$!u", $title->getText(), $m ) ); + if ( $isCssOrJsPage ) $ext = $m[1]; + + # hook can force js/css + wfRunHooks( 'TitleIsCssOrJsPage', array( $title, &$isCssOrJsPage, &$ext ) ); #FIXME: add $ext to hook interface spec + + # Is this a .css subpage of a user page? + $isJsCssSubpage = ( NS_USER == $ns && !$isCssOrJsPage && preg_match( "/\\/.*\\.(js|css)$/", $title->getText(), $m ) ); + if ( $isJsCssSubpage ) $ext = $m[1]; + + # is this wikitext, according to $wgNamespaceContentModels or the DefaultModelFor hook? + $isWikitext = ( $model == CONTENT_MODEL_WIKITEXT || $model === null ); + $isWikitext = ( $isWikitext && !$isCssOrJsPage && !$isJsCssSubpage ); + + # hook can override $isWikitext + wfRunHooks( 'TitleIsWikitextPage', array( $title, &$isWikitext ) ); + + if ( !$isWikitext ) { + + if ( $ext == 'js' ) + return CONTENT_MODEL_JAVASCRIPT; + else if ( $ext == 'css' ) + return CONTENT_MODEL_CSS; + + if ( $model ) + return $model; + else + return CONTENT_MODEL_TEXT; + } + + # we established that is must be wikitext + return CONTENT_MODEL_WIKITEXT; + } + + public static function getForTitle( Title $title ) { + $modelName = $title->getContentModelName(); + return ContenteHandler::getForModelName( $modelName ); + } + + public static function getForContent( Content $content ) { + $modelName = $content->getModelName(); + return ContenteHandler::getForModelName( $modelName ); + } + + public static function getForModelName( $modelName ) { + global $wgContentHandlers; + + if ( empty( $wgContentHandlers[$modelName] ) ) { + #FIXME: hook here! + throw new MWException( "No handler for model $modelName registered in \$wgContentHandlers" ); + } + + if ( is_string( $wgContentHandlers[$modelName] ) ) { + $class = $wgContentHandlers[$modelName]; + $wgContentHandlers[$modelName] = new $class( $modelName ); + } + + return $wgContentHandlers[$modelName]; + } + + public function __construct( $modelName, $formats ) { $this->mModelName = $modelName; $this->mSupportedFormats = $formats; @@ -62,7 +145,7 @@ abstract class ContentHandler { # returns a ParserOutput instance! # are parser options, generic?! - public function doPreSaveTransform( $title, $obj ); + public abstract function doPreSaveTransform( $title, $obj ); # TODO: getPreloadText() # TODO: preprocess() diff --git a/includes/DefaultSettings.php b/includes/DefaultSettings.php index c0ef5b391e..9536258580 100644 --- a/includes/DefaultSettings.php +++ b/includes/DefaultSettings.php @@ -636,6 +636,17 @@ $wgMediaHandlers = array( 'image/x-djvu' => 'DjVuHandler', // compat ); +/** + * Plugins for page content model handling. + * Each entry in the array maps a model name type to a class name + */ +$wgContentHandlers = array( + CONTENT_MODEL_WIKITEXT => 'WikitextContentHandler', // the usual case + CONTENT_MODEL_JAVASCRIPT => 'JavaScriptContentHandler', // dumb version, no syntax highlighting + CONTENT_MODEL_CSS => 'CssContentHandler', // dumb version, no syntax highlighting + CONTENT_MODEL_TEXT => 'TextContentHandler', // dumb plain text in
+);
+
 /**
  * Resizing can be done using PHP's internal image libraries or using
  * ImageMagick or another third-party converter, e.g. GraphicMagick.
diff --git a/includes/Defines.php b/includes/Defines.php
index 26deb2baf3..ea053017c4 100644
--- a/includes/Defines.php
+++ b/includes/Defines.php
@@ -249,3 +249,12 @@ define( 'PROTO_RELATIVE', '//' );
 define( 'PROTO_CURRENT', null );
 define( 'PROTO_CANONICAL', 1 );
 define( 'PROTO_INTERNAL', 2 );
+
+/**
+ * Content model names, used by Content and ContentHandler
+ */
+define('CONTENT_MODEL_WIKITEXT', 'wikitext');
+define('CONTENT_MODEL_JAVASCRIPT', 'javascript');
+define('CONTENT_MODEL_CSS', 'css');
+define('CONTENT_MODEL_TEXT', 'text');
+
diff --git a/includes/EditPage.php b/includes/EditPage.php
index 29aaee8e53..0f32c702b6 100644
--- a/includes/EditPage.php
+++ b/includes/EditPage.php
@@ -2552,6 +2552,7 @@ HTML
 		# don't parse non-wikitext pages, show message about preview
 		# XXX: stupid php bug won't let us use $this->getContextTitle()->isCssJsSubpage() here -- This note has been there since r3530. Sure the bug was fixed time ago?
 
+        #FIXME: get appropriate content handler!
 		if ( $this->isCssJsSubpage || !$this->mTitle->isWikitextPage() ) {
 			if( $this->mTitle->isCssJsSubpage() ) {
 				$level = 'user';
@@ -2564,6 +2565,7 @@ HTML
 			# Used messages to make sure grep find them:
 			# Messages: usercsspreview, userjspreview, sitecsspreview, sitejspreview
 			if( $level ) {
+			    #FIXME: move this crud into ContentHandler class!
 				if (preg_match( "/\\.css$/", $this->mTitle->getText() ) ) {
 					$previewtext = "
\n" . wfMsg( "{$level}csspreview" ) . "\n
"; $class = "mw-code mw-css"; diff --git a/includes/Revision.php b/includes/Revision.php index b254e81026..4e2a091d0c 100644 --- a/includes/Revision.php +++ b/includes/Revision.php @@ -20,6 +20,8 @@ class Revision { protected $mTextRow; protected $mTitle; protected $mCurrent; + protected $mContentModelName; + protected $mContentType; const DELETED_TEXT = 1; const DELETED_COMMENT = 2; @@ -125,6 +127,8 @@ class Revision { 'deleted' => $row->ar_deleted, 'len' => $row->ar_len, 'sha1' => isset( $row->ar_sha1 ) ? $row->ar_sha1 : null, + 'content_model' => isset( $row->ar_content_model ) ? $row->ar_content_model : null, + 'content_type' => isset( $row->ar_content_type ) ? $row->ar_content_type : null, ); if ( isset( $row->ar_text ) && !$row->ar_text_id ) { // Pre-1.5 ar_text row @@ -412,6 +416,18 @@ class Revision { $this->mTitle = null; } + if( !isset( $row->rev_content_model ) || is_null( $row->rev_content_model ) ) { + $this->mContentModelName = null; # determine on demand if needed + } else { + $this->mContentModelName = strval( $row->rev_content_model ); + } + + if( !isset( $row->rev_content_type ) || is_null( $row->rev_content_type ) ) { + $this->mContentType = null; # determine on demand if needed + } else { + $this->mContentType = strval( $row->rev_content_type ); + } + // Lazy extraction... $this->mText = null; if( isset( $row->old_text ) ) { @@ -445,6 +461,15 @@ class Revision { $this->mParentId = isset( $row['parent_id'] ) ? intval( $row['parent_id'] ) : null; $this->mSha1 = isset( $row['sha1'] ) ? strval( $row['sha1'] ) : null; + $this->mContentModelName = isset( $row['content_model'] ) ? strval( $row['content_model'] ) : null; + $this->mContentType = isset( $row['content_type'] ) ? strval( $row['content_type'] ) : null; + + if( !isset( $row->rev_content_type ) || is_null( $row->rev_content_type ) ) { + $this->mContentType = null; # determine on demand if needed + } else { + $this->mContentType = $row->rev_content_type; + } + // Enforce spacing trimming on supplied text $this->mComment = isset( $row['comment'] ) ? trim( strval( $row['comment'] ) ) : null; $this->mText = isset( $row['text'] ) ? rtrim( strval( $row['text'] ) ) : null; @@ -460,6 +485,9 @@ class Revision { if ( $this->mSha1 === null ) { $this->mSha1 = is_null( $this->mText ) ? null : self::base36Sha1( $this->mText ); } + + $this->getContentModelName(); # force lazy init + $this->getContentType(); # force lazy init } else { throw new MWException( 'Revision constructor passed invalid row format.' ); } @@ -723,17 +751,48 @@ class Revision { * @param $user User object to check for, only if FOR_THIS_USER is passed * to the $audience parameter * @return String + * @deprectaed in 1.20, use getContent() instead */ - public function getText( $audience = self::FOR_PUBLIC, User $user = null ) { - if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_TEXT ) ) { - return ''; - } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_TEXT, $user ) ) { - return ''; - } else { - return $this->getRawText(); - } + public function getText( $audience = self::FOR_PUBLIC, User $user = null ) { #FIXME: deprecated, replace usage! + wfDeprecated( __METHOD__, '1.20' ); + $content = $this->getContent(); + + if ( $content == null ) { + return ""; # not allowed + } + + if ( $content instanceof TextContent ) { + #FIXME: or check by model name? or define $content->allowRawData()? + return $content->getRawData(); + } + + #TODO: log this failure! + return null; } + /** + * Fetch revision content if it's available to the specified audience. + * If the specified audience does not have the ability to view this + * revision, null will be returned. + * + * @param $audience Integer: one of: + * Revision::FOR_PUBLIC to be displayed to all users + * Revision::FOR_THIS_USER to be displayed to $wgUser + * Revision::RAW get the text regardless of permissions + * @param $user User object to check for, only if FOR_THIS_USER is passed + * to the $audience parameter + * @return Content + */ + public function getContent( $audience = self::FOR_PUBLIC, User $user = null ) { + if( $audience == self::FOR_PUBLIC && $this->isDeleted( self::DELETED_TEXT ) ) { + return null; + } elseif( $audience == self::FOR_THIS_USER && !$this->userCan( self::DELETED_TEXT, $user ) ) { + return null; + } else { + return $this->getContentInternal(); + } + } + /** * Alias for getText(Revision::FOR_THIS_USER) * @@ -750,14 +809,55 @@ class Revision { * * @return String */ - public function getRawText() { - if( is_null( $this->mText ) ) { - // Revision text is immutable. Load on demand: - $this->mText = $this->loadText(); - } - return $this->mText; + public function getRawText() { #FIXME: deprecated, replace usage! + return $this->getText( self::RAW ); } + protected function getContentInternal() { + if( is_null( $this->mContent ) ) { + // Revision is immutable. Load on demand: + + $handler = $this->getContentHandler(); + $type = $this->getContentType(); + + if( is_null( $this->mText ) ) { + // Load text on demand: + $this->mText = $this->loadText(); + } + + $this->mContent = $handler->unserialize( $this->mText, $type ); + } + + return $this->mContent; + } + + public function getContentModelName() { + if ( !$this->mContentModelName ) { + $title = $this->getTitle(); #XXX: never null? + $this->mContentModelName = $title->getContentModelName(); + } + + return $this->mContentModelName; + } + + public function getContentType() { + if ( !$this->mContentType ) { + $handler = $this->getContentHandler(); + $this->mContentType = $handler->getDefaultFormat(); + } + + return $this->mContentType; + } + + public function getContentHandler() { + if ( !$this->mContentHandler ) { + $m = $this->getModelName(); + $this->mContentHandler = ContentHandler::getForModelName( $m ); + } + + return $this->mContentHandler; + } + /** * @return String */ @@ -996,7 +1096,9 @@ class Revision { : $this->mParentId, 'rev_sha1' => is_null( $this->mSha1 ) ? Revision::base36Sha1( $this->mText ) - : $this->mSha1 + : $this->mSha1, + 'rev_content_model' => $this->getContentModelName(), + 'rev_content_type' => $this->getContentType(), ), __METHOD__ ); @@ -1096,7 +1198,8 @@ class Revision { $current = $dbw->selectRow( array( 'page', 'revision' ), - array( 'page_latest', 'rev_text_id', 'rev_len', 'rev_sha1' ), + array( 'page_latest', 'rev_text_id', 'rev_len', 'rev_sha1', + 'rev_content_model', 'rev_content_type' ), array( 'page_id' => $pageId, 'page_latest=rev_id', @@ -1111,7 +1214,9 @@ class Revision { 'text_id' => $current->rev_text_id, 'parent_id' => $current->page_latest, 'len' => $current->rev_len, - 'sha1' => $current->rev_sha1 + 'sha1' => $current->rev_sha1, + 'content_model' => $current->rev_content_model, + 'content_type' => $current->rev_content_type ) ); } else { $revision = null; diff --git a/includes/Title.php b/includes/Title.php index b91c55c1d8..a52f353b1c 100644 --- a/includes/Title.php +++ b/includes/Title.php @@ -272,12 +272,17 @@ class Title { if ( isset( $row->page_is_redirect ) ) $this->mRedirect = (bool)$row->page_is_redirect; if ( isset( $row->page_latest ) ) - $this->mLatestID = (int)$row->page_latest; + $this->mLatestID = (int)$row->page_latest; # FIXME: whene3ver page_latest is updated, also update page_content_model + if ( isset( $row->page_content_model ) ) + $this->mContentModelName = $row->page_content_model; + else + $this->mContentModelName = null; # initialized lazily in getContentModelName() } else { // page not found $this->mArticleID = 0; $this->mLength = 0; $this->mRedirect = false; $this->mLatestID = 0; + $this->mContentModelName = null; # initialized lazily in getContentModelName() } } @@ -303,6 +308,7 @@ class Title { $t->mArticleID = ( $ns >= 0 ) ? -1 : 0; $t->mUrlform = wfUrlencode( $t->mDbkeyform ); $t->mTextform = str_replace( '_', ' ', $title ); + $t->mContentModelName = null; # initialized lazily in getContentModelName() return $t; } @@ -688,6 +694,29 @@ class Title { return $this->mNamespace; } + /** + * Get the page's content model name + * + * @return Integer: Namespace index + */ + public function getContentModelName() { + if ( empty( $this->mContentModelName ) ) { + $this->mContentModelName = ContentHandler::getDefaultModelFor( $this ); + } + + return $this->mContentModelName; + } + + /** + * Conveniance method for checking a title's content model name + * + * @param $name + * @return true if $this->getContentModelName() == $name + */ + public function hasContentModel( $name ) { + return $this->getContentModelName() == $name; + } + /** * Get the namespace text * @@ -937,9 +966,7 @@ class Title { * @return Bool */ public function isWikitextPage() { - $retval = !$this->isCssOrJsPage() && !$this->isCssJsSubpage(); - wfRunHooks( 'TitleIsWikitextPage', array( $this, &$retval ) ); - return $retval; + return $this->hasContentModel( CONTENT_MODEL_WIKITEXT ); } /** @@ -949,10 +976,8 @@ class Title { * @return Bool */ public function isCssOrJsPage() { - $retval = $this->mNamespace == NS_MEDIAWIKI - && preg_match( '!\.(?:css|js)$!u', $this->mTextform ) > 0; - wfRunHooks( 'TitleIsCssOrJsPage', array( $this, &$retval ) ); - return $retval; + return $this->hasContentModel( CONTENT_MODEL_CSS ) + || $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ); } /** @@ -960,7 +985,8 @@ class Title { * @return Bool */ public function isCssJsSubpage() { - return ( NS_USER == $this->mNamespace and preg_match( "/\\/.*\\.(?:css|js)$/", $this->mTextform ) ); + return ( NS_USER == $this->mNamespace && $this->isSubpage() + && $this->isCssOrJsPage() ); } /** @@ -983,7 +1009,8 @@ class Title { * @return Bool */ public function isCssSubpage() { - return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.css$/", $this->mTextform ) ); + return ( NS_USER == $this->mNamespace && $this->isSubpage() + && $this->hasContentModel( CONTENT_MODEL_CSS ) ); } /** @@ -992,7 +1019,8 @@ class Title { * @return Bool */ public function isJsSubpage() { - return ( NS_USER == $this->mNamespace && preg_match( "/\\/.*\\.js$/", $this->mTextform ) ); + return ( NS_USER == $this->mNamespace && $this->isSubpage() + && $this->hasContentModel( CONTENT_MODEL_JAVASCRIPT ) ); } /** diff --git a/includes/WikiPage.php b/includes/WikiPage.php index 468538f3d7..a0709b8891 100644 --- a/includes/WikiPage.php +++ b/includes/WikiPage.php @@ -800,7 +800,7 @@ class WikiPage extends Page { && $parserOptions->getStubThreshold() == 0 && $this->mTitle->exists() && ( $oldid === null || $oldid === 0 || $oldid === $this->getLatest() ) - && $this->mTitle->isWikitextPage(); + && $this->mTitle->isWikitextPage(); #FIXME: ask ContentHandler if cachable! } /** diff --git a/includes/parser/ParserOutput.php b/includes/parser/ParserOutput.php index 2877dcb00f..beeeb30a62 100644 --- a/includes/parser/ParserOutput.php +++ b/includes/parser/ParserOutput.php @@ -30,7 +30,7 @@ class CacheTime { */ function setCacheTime( $t ) { return wfSetVar( $this->mCacheTime, $t ); } - /** + /**abstract * Sets the number of seconds after which this object should expire. * This value is used with the ParserCache. * If called with a value greater than the value provided at any previous call,