Repository: TiddlyWiki/TiddlyWiki5 (JavaScript)

Issue:
[BUG]  TiddlyWiki 5.3.4 Prerelease: Transcluding Text References
### Describe the bug

The `transcludes` filter operator causes a RSOD when a tiddler contains transcluding text references like `{{!!title}}` or `{{!!created}}`

### Expected behavior

The `transclude` filter operator shall handle correctly the `{{!!any-field}}`

### To Reproduce

1. Go to https://tiddlywiki.com/prerelease/
2. Create a new tiddler
3. Put below script as text and save
```
{{!!created}}
....

<$list filter="[all[current]transcludes[]]">

</$list>
```
5. See error:  Uncaught Linked List only accepts string values, not undefined





NOTE: The below code works fine

```
{{New Tiddler!!created}}

<$list filter="[all[current]transcludes[]]">

</$list>
```


### Screenshots

![image](https://github.com/Jermolene/TiddlyWiki5/assets/830394/82173062-c238-49dc-9f1b-0237d888d35d)

### TiddlyWiki Configuration

- Version 5.3.4p
- [Saving mechanism [e.g. Node.js, TiddlyDesktop, TiddlyHost etc]](https://tiddlywiki.com/prerelease/)
- Windows 11
- Edge 125

### Additional context

_No response_


Discussion:
@linonetwo could you please have a look? I suspect we need handling for text references in the traversal of the parse tree.
**Another bug**

I suggest that the transcludes filter operator should works like link. The current implementation is problematic. It should not recognize soft transclusions like

```
<$tiddler tiddler="One">
<$transclude $tiddler />
</$tiddler>

<<list-links "[all[current]transcludes[]]">>
```

Strangely the below does not work

```
<$tiddler tiddler="One">
<$transclude $tiddler=<<currentTiddler>> />
</$tiddler>

<<list-links "[all[current]transcludes[]]">>
```




I propose only these forms shall be recognized:

```
{{mtTid}}
{{myTid||yourtemplate}}
{{myTid!!thatfield}}
{{myTid##thatindex}}
```

This `{{!!myfield}} ` does not make sense, if it refers to host tiddler, then we do not need it
If it refers to another tiddler, then some script is needed like `<$tiddler tiddler=...` or `<$list filter="..." > ....`
Thanks for testing, I should ignore the case where target tiddler is empty.
@linonetwo 
The below returns One, but it should not! Do you think this is an error with `<$transclude $tiddler />`

```
<$tiddler tiddler="One">
<$transclude $tiddler />
</$tiddler>

<<list-links "[all[current]transcludes[]]">>
```

This one returns nothing
```
<$tiddler tiddler="One">
<$transclude />
</$tiddler>

<<list-links "[all[current]transcludes[]]">>
```
Thank you @kookma I really appreciate the work you're putting into testing this, very helpful!
> The below returns One, but it should not! Do you think this is an error with `<$transclude $tiddler />`
> 
> ```
> <$tiddler tiddler="One">
> <$transclude $tiddler />
> </$tiddler>
> 
> <<list-links "[all[current]transcludes[]]">>
> ```

This bug also exists with `backtranscludes` operator.  So, if in tiddler One you put `<<list-links "[all[current]backtranscludes[]]">>` where the above code in in Tiddler Test, you get Text as backtransclude, but you should not get such answer!
@kookma Comparing with backlinks operator, and tagging operator, maybe we still need to include the tiddler itself. Maybe it will be useful someday? And user can always ` -[<currentTiddler>]` from it.
> @kookma Comparing with backlinks operator, and tagging operator, maybe we still need to include the tiddler itself. Maybe it will be useful someday? And user can always ` -[<currentTiddler>]` from it.

Well, from bidirectional note taking point of view, refereeing to itself makes no sense to me! but let's what other says.



Patch:
diff --git a/core/modules/wiki.js b/core/modules/wiki.js
index 96e40a708ac..2850dec5fff 100755
--- a/core/modules/wiki.js
+++ b/core/modules/wiki.js
@@ -567,7 +567,7 @@ exports.extractTranscludes = function(parseTreeRoot) {
 					} else {
 						value = parseTreeNode.attributes.$tiddler.value;
 					}
-					if(transcludes.indexOf(value) === -1) {
+					if(transcludes.indexOf(value) === -1 && value !== undefined) {
 						transcludes.push(value);
 					}
 				}


Test patch:
diff --git a/editions/test/tiddlers/tests/test-backtranscludes.js b/editions/test/tiddlers/tests/test-backtranscludes.js
index 8ef997566e4..fe6d097060b 100644
--- a/editions/test/tiddlers/tests/test-backtranscludes.js
+++ b/editions/test/tiddlers/tests/test-backtranscludes.js
@@ -11,7 +11,7 @@ Tests the backtranscludes mechanism.
 /*global $tw: false */
 "use strict";
 
-describe('Backtranscludes tests', function() {
+describe('Backtranscludes and transclude filter tests', function() {
 	describe('a tiddler with no transcludes to it', function() {
 		var wiki = new $tw.Wiki();
 
@@ -56,6 +56,26 @@ describe('Backtranscludes tests', function() {
 		});
 	});
 
+	describe('A data tiddler transclude will still use the tiddler as result.', function() {
+		var wiki = new $tw.Wiki();
+
+		wiki.addTiddler({
+			title: 'TestIncoming',
+			type: 'application/x-tiddler-dictionary',
+			text: 'name: value'});
+
+		wiki.addTiddler({
+			title: 'TestOutgoing',
+			text: 'A transclude to {{TestIncoming##name}}'});
+
+		it('should have a backtransclude', function() {
+			expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
+		});
+		it('should have a transclude', function() {
+			expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('TestIncoming');
+		});
+	});
+
 	describe('A tiddler that has a transclude added to it later', function() {
 		it('should have an additional backtransclude', function() {
 			var wiki = new $tw.Wiki();
@@ -143,6 +163,56 @@ describe('Backtranscludes tests', function() {
 			expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('');
 		});
 	});
+
+	describe('a tiddler with some transcludes on it in order', function() {
+		var wiki = new $tw.Wiki();
+
+		wiki.addTiddler({
+			title: 'TestOutgoing',
+			text: "{{New Tiddler!!created}}\n\nA transclude to {{TestIncoming}}"
+		});
+
+		it('should have a transclude', function() {
+			expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('New Tiddler,TestIncoming');
+		});
+
+		it('should have a back transclude', function() {
+			expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
+			expect(wiki.filterTiddlers('[[New Tiddler]] +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
+		});
+	});
+
+	describe('ignore self transclusion', function() {
+		var wiki = new $tw.Wiki();
+
+		wiki.addTiddler({
+			title: 'TestOutgoing',
+			text: "{{!!created}}\n\nA transclude to {{!!title}}"});
+
+		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();
+
+		wiki.addTiddler({
+			title: 'TestOutgoing',
+			text: "<$tiddler tiddler='TestIncoming'><$transclude $tiddler /></$tiddler>"});
+
+		it('should have a transclude', function() {
+			expect(wiki.filterTiddlers('TestOutgoing +[transcludes[]]').join(',')).toBe('TestIncoming');
+		});
+
+		it('should have a back transclude', function() {
+			expect(wiki.filterTiddlers('TestIncoming +[backtranscludes[]]').join(',')).toBe('TestOutgoing');
+		});
+	});
 });
 
 })();