From 78d1bd1570785df0099e0cf6ac4565556b4f82fc Mon Sep 17 00:00:00 2001 From: lin onetwo Date: Wed, 12 Jun 2024 21:12:27 +0800 Subject: [PATCH] fix: ignore self-referential transclusion --- core/modules/indexers/back-indexer.js | 2 +- core/modules/wiki.js | 10 ++++++---- .../tiddlers/tests/test-backtranscludes.js | 18 +++++++++++++++++- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/core/modules/indexers/back-indexer.js b/core/modules/indexers/back-indexer.js index b9daf3328..77b51b819 100644 --- a/core/modules/indexers/back-indexer.js +++ b/core/modules/indexers/back-indexer.js @@ -75,7 +75,7 @@ BackSubIndexer.prototype._getTarget = function(tiddler) { } var parser = this.wiki.parseText(tiddler.fields.type, tiddler.fields.text, {}); if(parser) { - return this.wiki[this.extractor](parser.tree); + return this.wiki[this.extractor](parser.tree, tiddler.fields.title); } return []; } diff --git a/core/modules/wiki.js b/core/modules/wiki.js index 2850dec5f..44e09cfde 100755 --- a/core/modules/wiki.js +++ b/core/modules/wiki.js @@ -551,9 +551,9 @@ exports.getTiddlerBacklinks = function(targetTitle) { /* -Return an array of tiddler titles that are directly transcluded within the given parse tree +Return an array of tiddler titles that are directly transcluded within the given parse tree. `title` is the tiddler being parsed, we will ignore its self-referential transclusions, only return */ -exports.extractTranscludes = function(parseTreeRoot) { +exports.extractTranscludes = function(parseTreeRoot, title) { // Count up the transcludes var transcludes = [], checkParseTree = function(parseTree, parentNode) { @@ -567,7 +567,8 @@ exports.extractTranscludes = function(parseTreeRoot) { } else { value = parseTreeNode.attributes.$tiddler.value; } - if(transcludes.indexOf(value) === -1 && value !== undefined) { + // ignore empty value (like `{{!!field}}`), and deduplicate + if(value && transcludes.indexOf(value) === -1 && value !== title) { transcludes.push(value); } } @@ -591,7 +592,8 @@ exports.getTiddlerTranscludes = function(title) { // Parse the tiddler var parser = self.parseTiddler(title); if(parser) { - return self.extractTranscludes(parser.tree); + // this will ignore self-referential transclusions from `title` + return self.extractTranscludes(parser.tree, title); } return []; }); diff --git a/editions/test/tiddlers/tests/test-backtranscludes.js b/editions/test/tiddlers/tests/test-backtranscludes.js index fe6d09706..f0ecd26f0 100644 --- a/editions/test/tiddlers/tests/test-backtranscludes.js +++ b/editions/test/tiddlers/tests/test-backtranscludes.js @@ -187,7 +187,7 @@ describe('Backtranscludes and transclude filter tests', function() { wiki.addTiddler({ title: 'TestOutgoing', - text: "{{!!created}}\n\nA transclude to {{!!title}}"}); + text: "{{!!created}}\n\nAn implicit self-referential transclude to <$transclude $field='created'/> and <$transclude field='created'/>"}); it('should have no transclude', function() { expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe(''); @@ -198,6 +198,22 @@ describe('Backtranscludes and transclude filter tests', function() { }); }); + describe('Explicit self transclusion', function() { + var wiki = new $tw.Wiki(); + + wiki.addTiddler({ + title: 'TestOutgoing', + text: "{{TestOutgoing!!created}}\n\n<$transclude $tiddler='TestOutgoing' $field='created'/> and <$transclude tiddler='TestOutgoing' field='created'/>"}); + + it('should have no transclude', function() { + expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe(''); + }); + + it('should have no back transcludes', function() { + expect(wiki.filterTiddlers('TestOutgoing +[backtranscludes[]]').join(',')).toBe(''); + }); + }); + describe('recognize soft transclusion defined by widget', function() { var wiki = new $tw.Wiki();