Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-26165] iOS: Requiring a JSON file that contains single quotes throws error

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionFixed
Resolution Date2018-08-24T17:23:21.000+0000
Affected Version/sRelease 7.1.1, Release 7.2.0
Fix Version/sRelease 7.5.0
ComponentsiOS
Labelsios, json, parity
ReporterEwan Harris
AssigneeHans Knöchel
Created2018-06-28T11:27:25.000+0000
Updated2018-08-24T17:23:53.000+0000

Description

Description

When requiring a JSON file where a value contains a single quote an error like below is thrown, this works fine on Windows/Android
[ERROR] Script Error {
[ERROR]     column = 32;
[ERROR]     line = 2;
[ERROR]     message = "Unexpected identifier 's'. Expected ')' to end an argument list.";
[ERROR]     sourceURL = "file:///Users/eharris/Library/Developer/CoreSimulator/Devices/EE6CA02F-4F3A-4407-9929-FEAC97512C66/data/Containers/Bundle/Application/4B53071A-F963-4006-9FEC-DA1C01E87548/ticreateapp.app/jsonfile.json";
[ERROR]     stack = "    at require@[native code]\n    at global code(/app.js:1:32)";
[ERROR] }
[ERROR] Script Error Module "jsonfile.json" failed to leave a valid exports object
*Workaround* Read the file in like JSON.parse(Ti.Filesystem.getFile('file.json').read())

Steps to reproduce

Add the below into a JSON file under your project

{
	"foo": "Singlequotes can ruin one's day"
}

Add a require statement into your code that requires the file

Actual

Error like the above is thrown

Expected

File should be imported

Attachments

FileDateSize
amber.json2018-06-28T18:48:19.000+00008109

Comments

  1. Hans Knöchel 2018-06-28

    Could you check if that also happened before SDK 6.2.0? It may be caused by https://github.com/appcelerator/titanium_mobile/pull/9106 then.
  2. Ewan Harris 2018-06-28

    [~hknoechel] It still occurs on 6.1.1.GA, I think the [logic for require-ing a JSON file](https://github.com/appcelerator/titanium_mobile/blob/eeffeedd4bc7f20ad5211b69461c0e9b128c0d7b/iphone/Classes/KrollBridge.m#L890-L907) doesn't pass through there from what I can see. Maybe it should?
  3. Ewan Harris 2018-06-28

    Changing [this line](https://github.com/appcelerator/titanium_mobile/blob/eeffeedd4bc7f20ad5211b69461c0e9b128c0d7b/iphone/Classes/KrollBridge.m#L899) to {noformat} data = [data stringByReplacingOccurrencesOfString:@"'" withString:@"\\'"]; {noformat} fixes for the original issue, but still errors out on the attached amber.json with the below
       [ERROR] Script Error {
       [ERROR]     column = 143;
       [ERROR]     line = 1;
       [ERROR]     message = "JSON Parse error: Unterminated string";
       [ERROR]     sourceURL = "file:///Users/eharris/Library/Developer/CoreSimulator/Devices/EE6CA02F-4F3A-4407-9929-FEAC97512C66/data/Containers/Bundle/Application/E4B9915B-D15D-420F-95F1-935C3F4CC4EB/Amber.app/amber.json";
       [ERROR]     stack = "    at parse@[native code]\n    at (/amber.json:1:143)\n    at global code(/amber.json:75:70)\n    at require@[native code]\n    at global code(/app.js:1:20)";
       [ERROR] }
       [ERROR] Script Error Module "amber.json" failed to leave a valid exports object
       
  4. Hans Knöchel 2018-06-28

    There built-in serializer classes in iOS these days (I think iOS7+). I will try to refactor the JSON-import logic using NSJSONSerialization, which has options to handle how the JSON should be serialized and which parts of it should be retained how. *EDIT*: This here works fine:
       var win = Ti.UI.createWindow({
           backgroundColor: '#fff'
       });
       
       var btn = Ti.UI.createButton({
           title: 'Trigger'
       });
       
       btn.addEventListener('click', function() {
           try {
               var payload = JSON.parse(Ti.Filesystem.getFile('amber.json').read());
               alert('SDK: ' + payload.sdk);
           } catch (e) {
               Ti.API.error('Error parsing JSON: \n' + e);
           }
       });
       
       win.add(btn);
       win.open();
       
  5. Ewan Harris 2018-08-07

    [~hknoechel] Reading the file and JSON.parse'ing it works fine, but it doesn't work from require. The file is valid as it works on Titanium Windows/Android and Node. What extra info is needed?
  6. Hans Knöchel 2018-08-07

    Reopening since it is reproducible with the following test-case:
       var amber = require('amber'); // expects a "amber.json" to be in the resources
       
       var win = Ti.UI.createWindow({
           backgroundColor: '#fff'
       });
       
       win.open();
       
  7. Hans Knöchel 2018-08-07

    Fixed it. We can use native JSON-parse/stringify methods for this nowadays. PR: https://github.com/appcelerator/titanium_mobile/pull/10238 Test-Case:
       var amber = require('amber'); // Looks for "amber.json" in Resources/ (classic) or app/assets (Alloy)
       
       var win = Ti.UI.createWindow({
           backgroundColor: '#fff'
       });
       
       var btn = Ti.UI.createButton({
           title: 'Trigger'
       });
       
       btn.addEventListener('click', function() {
           Ti.API.info(amber.sdk);
       });
       
       win.add(btn);
       win.open();
       
    Expected result: A console log with "7.4.0.v20180627024922".
  8. Samir Mohammed 2018-08-15

JSON Source