Refactor the file-system-access API to be synchronous. Added *Sync equivalents of the file-system APIs. Removed usage of file-system-access within the code.

This commit is contained in:
atanasovg
2015-08-04 16:52:27 +03:00
parent 114118bc7a
commit c683ea44e6
13 changed files with 370 additions and 361 deletions

View File

@ -1,7 +1,6 @@
require("globals"); require("globals");
import definition = require("application"); import definition = require("application");
import fs = require("file-system"); import fs = require("file-system");
import fileSystemAccess = require("file-system/file-system-access");
import styleScope = require("ui/styling/style-scope"); import styleScope = require("ui/styling/style-scope");
import observable = require("data/observable"); import observable = require("data/observable");
@ -41,8 +40,8 @@ export function loadCss() {
var cssFileName = fs.path.join(fs.knownFolders.currentApp().path, definition.cssFile); var cssFileName = fs.path.join(fs.knownFolders.currentApp().path, definition.cssFile);
var applicationCss; var applicationCss;
if (fs.File.exists(cssFileName)) { if (fs.File.exists(cssFileName)) {
new fileSystemAccess.FileSystemAccess().readText(cssFileName, r => { applicationCss = r; }); var file = fs.File.fromPath(cssFileName);
definition.cssSelectorsCache = styleScope.StyleScope.createSelectorsFromCss(applicationCss, cssFileName); definition.cssSelectorsCache = styleScope.StyleScope.createSelectorsFromCss(file.readTextSync(), cssFileName);
} }
} }
} }

View File

@ -1,14 +1,25 @@
import TKUnit = require("../TKUnit"); import TKUnit = require("../TKUnit");
import fs = require("file-system"); import fs = require("file-system");
import fileSystemAccess = require("file-system/file-system-access");
var fileAccess = new fileSystemAccess.FileSystemAccess();
export var test_UTF8_BOM_is_not_returned = function () { export var test_UTF8_BOM_is_not_returned = function () {
var actualResult: string; var actualResult: string;
fileAccess.readText(fs.path.join(__dirname, "xml.expected"), (result) => { actualResult = result; }, (error) => { TKUnit.assert(false, "Could not read file utf8.txt"); }); var path = fs.path.join(__dirname, "xml.expected");
if (!fs.File.exists(path)) {
TKUnit.assert(false, "Could not read file utf8.txt");
return;
}
var actualCharCode = actualResult.charCodeAt(0); var file = fs.File.fromPath(path);
var expectedCharCode = "{".charCodeAt(0);
TKUnit.assert(actualCharCode === expectedCharCode, "Actual character code: " + actualCharCode + "; Expected character code: " + expectedCharCode); var onError = function (error) {
TKUnit.assert(false, "Could not read file utf8.txt");
}
var text = file.readTextSync(onError);
if (text) {
var actualCharCode = text.charCodeAt(0);
var expectedCharCode = "{".charCodeAt(0);
TKUnit.assert(actualCharCode === expectedCharCode, "Actual character code: " + actualCharCode + "; Expected character code: " + expectedCharCode);
}
}; };

View File

@ -9,7 +9,6 @@ import gridLayoutModule = require("ui/layouts/grid-layout");
import absoluteLayoutModule = require("ui/layouts/absolute-layout"); import absoluteLayoutModule = require("ui/layouts/absolute-layout");
import types = require("utils/types"); import types = require("utils/types");
import fs = require("file-system"); import fs = require("file-system");
import fileSystemAccess = require("file-system/file-system-access");
import observable = require("data/observable"); import observable = require("data/observable");
import stackLayoutModule = require("ui/layouts/stack-layout"); import stackLayoutModule = require("ui/layouts/stack-layout");
import labelModule = require("ui/label"); import labelModule = require("ui/label");
@ -129,24 +128,15 @@ export function test_loadWithOptionsFromTNSPath() {
}; };
export function test_parse_ShouldNotCrashWithoutExports() { export function test_parse_ShouldNotCrashWithoutExports() {
var fileAccess = new fileSystemAccess.FileSystemAccess(); var file = fs.File.fromPath(fs.path.join(__dirname, "mainPage.xml"));
var text = file.readTextSync();
var v: view.View;
fileAccess.readText(fs.path.join(__dirname, "mainPage.xml"), r => {
v = builder.parse(r);
});
var v: view.View = builder.parse(text);
TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";"); TKUnit.assert(v instanceof view.View, "Expected result: View; Actual result: " + v + ";");
}; };
export function test_parse_ShouldNotCrashWithInvalidXml() { export function test_parse_ShouldNotCrashWithInvalidXml() {
var fileAccess = new fileSystemAccess.FileSystemAccess(); var v: view.View = builder.parse("<Page loaded='myLoaded'></Pa");
var v: view.View;
fileAccess.readText("<Page loaded='myLoaded'></Pa", r => {
v = builder.parse(r);
});
TKUnit.assert(types.isUndefined(v), "Expected result: undefined; Actual result: " + v + ";"); TKUnit.assert(types.isUndefined(v), "Expected result: undefined; Actual result: " + v + ";");
}; };

View File

@ -9,8 +9,6 @@
import TKUnit = require("../TKUnit"); import TKUnit = require("../TKUnit");
import xmlModule = require("xml"); import xmlModule = require("xml");
import fs = require("file-system"); import fs = require("file-system");
import fileSystemAccess = require("file-system/file-system-access");
var fileAccess = new fileSystemAccess.FileSystemAccess();
export var test_XmlParser_IsDefined = function () { export var test_XmlParser_IsDefined = function () {
TKUnit.assert(typeof (xmlModule.XmlParser) !== "undefined", "Class XmlParser should be defined!"); TKUnit.assert(typeof (xmlModule.XmlParser) !== "undefined", "Class XmlParser should be defined!");
@ -83,14 +81,14 @@ export var test_XmlParser_IntegrationTest = function () {
actualResult += event.toString(); actualResult += event.toString();
}); });
var xmlString; var file = fs.File.fromPath(fs.path.join(__dirname, "xml.xml"));
fileAccess.readText(fs.path.join(__dirname, "xml.xml"), (result) => { xmlString = result; }); var xmlString = file.readTextSync();
xmlString = xmlString.replace(/(\r\n|\n|\r)/gm, "\n"); xmlString = xmlString.replace(/(\r\n|\n|\r)/gm, "\n");
xmlParser.parse(xmlString); xmlParser.parse(xmlString);
var expectedResult: string; var expectedResult: string;
fileAccess.readText(fs.path.join(__dirname, "xml.expected"), (result) => { expectedResult = result; }); file = fs.File.fromPath(fs.path.join(__dirname, "xml.expected"));
expectedResult = file.readTextSync();
var i; var i;
var maxLength = Math.max(actualResult.length, expectedResult.length); var maxLength = Math.max(actualResult.length, expectedResult.length);
@ -186,8 +184,7 @@ export var test_XmlParser_NamespacesTest = function () {
}, undefined, true); }, undefined, true);
var xmlString; var file = fs.File.fromPath(fs.path.join(__dirname, "xml-with-namespaces.xml"));
fileAccess.readText(fs.path.join(__dirname, "xml-with-namespaces.xml"), (result) => { xmlString = result; }); var xmlString = file.readTextSync();
xmlParser.parse(xmlString); xmlParser.parse(xmlString);
}; };

View File

@ -1,13 +1,11 @@
import observable = require("data/observable"); import observable = require("data/observable");
import fs = require("file-system"); import fs = require("file-system");
import fileSystemAccess = require("file-system/file-system-access");
var fileAccess = new fileSystemAccess.FileSystemAccess();
export class WebViewModel extends observable.Observable { export class WebViewModel extends observable.Observable {
constructor() { constructor() {
super(); super();
fileAccess.readText(fs.path.join(__dirname, "style.css"), (result) => { this._css = result; }); var file = fs.File.fromPath(fs.path.join(__dirname, "style.css"));
this._css = file.readTextSync();
} }
private _url: string; private _url: string;
@ -19,19 +17,6 @@ export class WebViewModel extends observable.Observable {
this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "url", value: value }); this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "url", value: value });
} }
//private _text: string;
//get text(): string {
// return this._text;
//}
//set text(value: string) {
// this._text = value;
// this.notify({ object: this, eventName: observable.Observable.propertyChangeEvent, propertyName: "text", value: value });
// if (application.ios) {
// this.url = this.text;
// }
//}
private _css: string; private _css: string;
get css(): string { get css(): string {
return this._css; return this._css;

View File

@ -48,11 +48,7 @@ export class FileSystemAccess {
this.enumEntities(path, onEntity, onError); this.enumEntities(path, onEntity, onError);
} }
public getEntities(path: string, onSuccess: (files: Array<{ path: string; name: string; extension: string }>) => any, onError?: (error: any) => any) { public getEntities(path: string, onError?: (error: any) => any): Array<{ path: string; name: string; extension: string }> {
if (!onSuccess) {
return;
}
var fileInfos = new Array<{ path: string; name: string; extension: string }>(); var fileInfos = new Array<{ path: string; name: string; extension: string }>();
var onEntity = function (entity: { path: string; name: string; extension: string }): boolean { var onEntity = function (entity: { path: string; name: string; extension: string }): boolean {
fileInfos.push(entity); fileInfos.push(entity);
@ -71,8 +67,10 @@ export class FileSystemAccess {
this.enumEntities(path, onEntity, localError); this.enumEntities(path, onEntity, localError);
if (!errorOccurred) { if (!errorOccurred) {
onSuccess(fileInfos); return fileInfos;
} }
return null;
} }
public fileExists(path: string): boolean { public fileExists(path: string): boolean {
@ -89,7 +87,7 @@ export class FileSystemAccess {
return exists && dir; return exists && dir;
} }
public deleteFile(path: string, onSuccess?: () => any, onError?: (error: any) => any) { public deleteFile(path: string, onError?: (error: any) => any) {
try { try {
var javaFile = new java.io.File(path); var javaFile = new java.io.File(path);
if (!javaFile.isFile()) { if (!javaFile.isFile()) {
@ -104,8 +102,6 @@ export class FileSystemAccess {
if (onError) { if (onError) {
onError({ message: "File deletion failed" }); onError({ message: "File deletion failed" });
} }
} else if (onSuccess) {
onSuccess();
} }
} catch (exception) { } catch (exception) {
if (onError) { if (onError) {
@ -114,7 +110,7 @@ export class FileSystemAccess {
} }
} }
public deleteFolder(path: string, isKnown?: boolean, onSuccess?: () => any, onError?: (error: any) => any) { public deleteFolder(path: string, onError?: (error: any) => any) {
try { try {
var javaFile = new java.io.File(path); var javaFile = new java.io.File(path);
if (!javaFile.getCanonicalFile().isDirectory()) { if (!javaFile.getCanonicalFile().isDirectory()) {
@ -125,27 +121,14 @@ export class FileSystemAccess {
return; return;
} }
if (isKnown) {
if (onError) {
onError({ message: "Cannot delete known folder." });
}
return;
}
// TODO: Asynchronous // TODO: Asynchronous
this.deleteFolderContent(javaFile); this.deleteFolderContent(javaFile);
if (javaFile.delete()) { if (!javaFile.delete()) {
if (onSuccess) {
onSuccess();
}
} else {
if (onError) { if (onError) {
onError({ message: "Folder deletion failed." }); onError({ message: "Folder deletion failed." });
} }
} }
} catch (exception) { } catch (exception) {
if (onError) { if (onError) {
onError(exception); onError(exception);
@ -153,7 +136,7 @@ export class FileSystemAccess {
} }
} }
public emptyFolder(path: string, onSuccess?: () => any, onError?: (error: any) => any) { public emptyFolder(path: string, onError?: (error: any) => any) {
try { try {
var javaFile = new java.io.File(path); var javaFile = new java.io.File(path);
if (!javaFile.getCanonicalFile().isDirectory()) { if (!javaFile.getCanonicalFile().isDirectory()) {
@ -166,11 +149,6 @@ export class FileSystemAccess {
// TODO: Asynchronous // TODO: Asynchronous
this.deleteFolderContent(javaFile); this.deleteFolderContent(javaFile);
if (onSuccess) {
onSuccess();
}
} catch (exception) { } catch (exception) {
if (onError) { if (onError) {
onError(exception); onError(exception);
@ -178,7 +156,7 @@ export class FileSystemAccess {
} }
} }
public rename(path: string, newPath: string, onSuccess?: () => any, onError?: (error: any) => any) { public rename(path: string, newPath: string, onError?: (error: any) => any) {
var javaFile = new java.io.File(path); var javaFile = new java.io.File(path);
if (!javaFile.exists()) { if (!javaFile.exists()) {
if (onError) { if (onError) {
@ -201,12 +179,6 @@ export class FileSystemAccess {
if (onError) { if (onError) {
onError(new Error("Failed to rename file '" + path + "' to '" + newPath + "'")); onError(new Error("Failed to rename file '" + path + "' to '" + newPath + "'"));
} }
return;
}
if (onSuccess) {
onSuccess();
} }
} }
@ -220,7 +192,7 @@ export class FileSystemAccess {
return dir.getAbsolutePath(); return dir.getAbsolutePath();
} }
public readText(path: string, onSuccess: (content: string) => any, onError?: (error: any) => any, encoding?: any) { public readText(path: string, onError?: (error: any) => any, encoding?: any) {
try { try {
var javaFile = new java.io.File(path); var javaFile = new java.io.File(path);
var stream = new java.io.FileInputStream(javaFile); var stream = new java.io.FileInputStream(javaFile);
@ -258,9 +230,7 @@ export class FileSystemAccess {
bufferedReader.close(); bufferedReader.close();
if (onSuccess) { return result;
onSuccess(result);
}
} catch (exception) { } catch (exception) {
if (onError) { if (onError) {
onError(exception); onError(exception);
@ -277,7 +247,7 @@ export class FileSystemAccess {
return s; return s;
} }
public writeText(path: string, content: string, onSuccess?: () => any, onError?: (error: any) => any, encoding?: any) { public writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any) {
try { try {
var javaFile = new java.io.File(path); var javaFile = new java.io.File(path);
var stream = new java.io.FileOutputStream(javaFile); var stream = new java.io.FileOutputStream(javaFile);
@ -290,10 +260,6 @@ export class FileSystemAccess {
writer.write(content); writer.write(content);
writer.close(); writer.close();
if (onSuccess) {
onSuccess();
}
} catch (exception) { } catch (exception) {
if (onError) { if (onError) {
onError(exception); onError(exception);

View File

@ -38,15 +38,15 @@
* @param onSuccess A callback function to call if operation is successful * @param onSuccess A callback function to call if operation is successful
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
*/ */
getEntities(path: string, onSuccess: (files: Array<{ path: string; name: string; extension: string }>) => any, onError?: (error: any) => any); getEntities(path: string, onError?: (error: any) => any): Array<{ path: string; name: string; extension: string }>;
/** /**
* Performs an action onSuccess for every entity in a folder with a given path. * Performs an action onSuccess for every entity in a folder with a given path.
* Breaks the loop if onSuccess function returns false * Breaks the loop if onSuccess function returns false
* @param onSuccess A callback function which is called for each entity. * @param onEntity A callback function which is called for each entity.
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
*/ */
eachEntity(path: string, onSuccess: (entity: { path: string; name: string; extension: string }) => boolean, onError?: (error: any) => any); eachEntity(path: string, onEntity: (entity: { path: string; name: string; extension: string }) => boolean, onError?: (error: any) => any);
/** /**
* Checks if a file with a given path exist. * Checks if a file with a given path exist.
@ -61,35 +61,31 @@
/** /**
* Deletes a file with a given path. * Deletes a file with a given path.
* @param path Path of the file. * @param path Path of the file.
* @param onSuccess (optional) A callback function which will be executed if the deletion is successful.
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
*/ */
deleteFile(path: string, onSuccess?: () => any, onError?: (error: any) => any); deleteFile(path: string, onError?: (error: any) => any);
/** /**
* Deletes a folder with a given path. * Deletes a folder with a given path.
* @param path Path of the folder. * @param path Path of the folder.
* @param onSuccess (optional) A callback function which will be executed if the deletion is successful.
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
*/ */
deleteFolder(path: string, isKnown: boolean, onSuccess?: () => any, onError?: (error: any) => any); deleteFolder(path: string, onError?: (error: any) => any);
/** /**
* Deletes a content of a folder with a given path. * Deletes a content of a folder with a given path.
* @param path Path of the folder. * @param path Path of the folder.
* @param onSuccess (optional) A callback function which will be executed if the deletion is successful.
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
*/ */
emptyFolder(path: string, onSuccess?: () => any, onError?: (error: any) => any): void; emptyFolder(path: string, onError?: (error: any) => any): void;
/** /**
* Rename a file or a folder with a given path. * Rename a file or a folder with a given path.
* @param path Current path of the entity which should be renamed. * @param path Current path of the entity which should be renamed.
* @param newPath The new path which will be asigned of the entity. * @param newPath The new path which will be asigned of the entity.
* @param onSuccess (optional) A callback function which will be executed if the deletion is successful.
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
*/ */
rename(path: string, newPath: string, onSuccess?: () => any, onError?: (error: any) => any): void; rename(path: string, newPath: string, onError?: (error: any) => any): void;
/** /**
* Gets the special documents folder. * Gets the special documents folder.
@ -110,7 +106,7 @@
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
* @param encoding (optional) If set reads the text with the specified encoding (default UTF-8). * @param encoding (optional) If set reads the text with the specified encoding (default UTF-8).
*/ */
readText(path: string, onSuccess: (content: string) => any, onError?: (error: any) => any, encoding?: any); readText(path: string, onError?: (error: any) => any, encoding?: any): string;
/** /**
* Writes a text to a file with a given path. * Writes a text to a file with a given path.
@ -120,7 +116,7 @@
* @param onError (optional) A callback function to use if any error occurs. * @param onError (optional) A callback function to use if any error occurs.
* @param encoding (optional) If set writes the text with the specified encoding (default UTF-8). * @param encoding (optional) If set writes the text with the specified encoding (default UTF-8).
*/ */
writeText(path: string, content: string, onSuccess?: () => any, onError?: (error: any) => any, encoding?: any); writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any);
/** /**
* Gets extension of the file with a given path. * Gets extension of the file with a given path.

View File

@ -120,12 +120,9 @@ export class FileSystemAccess {
this.enumEntities(path, onEntity, onError); this.enumEntities(path, onEntity, onError);
} }
public getEntities(path: string, onSuccess: (files: Array<{ path: string; name: string; extension: string }>) => any, onError?: (error: any) => any) { public getEntities(path: string, onError?: (error: any) => any): Array<{ path: string; name: string; extension: string }> {
if (!onSuccess) {
return;
}
var fileInfos = new Array<{ path: string; name: string; extension: string }>(); var fileInfos = new Array<{ path: string; name: string; extension: string }>();
var onEntity = function (entity: { path: string; name: string; extension: string }): boolean { var onEntity = function (entity: { path: string; name: string; extension: string }): boolean {
fileInfos.push(entity); fileInfos.push(entity);
return true; return true;
@ -143,8 +140,10 @@ export class FileSystemAccess {
this.enumEntities(path, onEntity, localError); this.enumEntities(path, onEntity, localError);
if (!errorOccurred) { if (!errorOccurred) {
onSuccess(fileInfos); return fileInfos;
} }
return null;
} }
public fileExists(path: string): boolean { public fileExists(path: string): boolean {
@ -169,49 +168,38 @@ export class FileSystemAccess {
return nsString.toString(); return nsString.toString();
} }
public deleteFile(path: string, onSuccess?: () => any, onError?: (error: any) => any) { public deleteFile(path: string, onError?: (error: any) => any) {
this.deleteEntity(path, onSuccess, onError); this.deleteEntity(path, onError);
} }
public deleteFolder(path: string, isKnown?: boolean, onSuccess?: () => any, onError?: (error: any) => any) { public deleteFolder(path: string, onError?: (error: any) => any) {
if (isKnown) { this.deleteEntity(path, onError);
if (onError) { }
onError({ message: "Cannot delete known folder." });
}
public emptyFolder(path: string, onError?: (error: any) => any) {
var fileManager = NSFileManager.defaultManager();
var entities = this.getEntities(path, onError);
if (!entities) {
return; return;
} }
this.deleteEntity(path, onSuccess, onError); var i;
} for (i = 0; i < entities.length; i++) {
try {
public emptyFolder(path: string, onSuccess?: () => any, onError?: (error: any) => any) { fileManager.removeItemAtPathError(entities[i].path);
var fileManager = NSFileManager.defaultManager();
var filesEnum = function (files: Array<{ path: string; name: string; extension: string }>) {
var i;
for (i = 0; i < files.length; i++) {
try {
fileManager.removeItemAtPathError(files[i].path);
}
catch (ex) {
if (onError) {
onError(new Error("Failed to empty folder '" + path + "': " + ex));
}
return;
}
} }
catch (ex) {
if (onError) {
onError(new Error("Failed to empty folder '" + path + "': " + ex));
}
if (onSuccess) { return;
onSuccess();
} }
} }
this.getEntities(path, filesEnum, onError);
} }
public rename(path: string, newPath: string, onSuccess?: () => any, onError?: (error: any) => any) { public rename(path: string, newPath: string, onError?: (error: any) => any) {
var fileManager = NSFileManager.defaultManager(); var fileManager = NSFileManager.defaultManager();
try { try {
@ -221,12 +209,6 @@ export class FileSystemAccess {
if (onError) { if (onError) {
onError(new Error("Failed to rename '" + path + "' to '" + newPath + "': " + ex)); onError(new Error("Failed to rename '" + path + "' to '" + newPath + "': " + ex));
} }
return;
}
if (onSuccess) {
onSuccess();
} }
} }
@ -238,7 +220,7 @@ export class FileSystemAccess {
return this.getKnownPath(this.cachesDir); return this.getKnownPath(this.cachesDir);
} }
public readText(path: string, onSuccess: (content: string) => any, onError?: (error: any) => any, encoding?: any) { public readText(path: string, onError?: (error: any) => any, encoding?: any) {
var actualEncoding = encoding; var actualEncoding = encoding;
if (!actualEncoding) { if (!actualEncoding) {
actualEncoding = textModule.encoding.UTF_8; actualEncoding = textModule.encoding.UTF_8;
@ -246,21 +228,16 @@ export class FileSystemAccess {
try { try {
var nsString = NSString.stringWithContentsOfFileEncodingError(path, actualEncoding); var nsString = NSString.stringWithContentsOfFileEncodingError(path, actualEncoding);
return nsString.toString();
} }
catch (ex) { catch (ex) {
if (onError) { if (onError) {
onError(new Error("Failed to read file at path '" + path + "': " + ex)); onError(new Error("Failed to read file at path '" + path + "': " + ex));
} }
return;
}
if (onSuccess) {
onSuccess(nsString.toString());
} }
} }
public writeText(path: string, content: string, onSuccess?: () => any, onError?: (error: any) => any, encoding?: any) { public writeText(path: string, content: string, onError?: (error: any) => any, encoding?: any) {
var nsString = NSString.alloc().initWithString(content); var nsString = NSString.alloc().initWithString(content);
var actualEncoding = encoding; var actualEncoding = encoding;
@ -276,12 +253,6 @@ export class FileSystemAccess {
if (onError) { if (onError) {
onError(new Error("Failed to write to file '" + path + "': " + ex)); onError(new Error("Failed to write to file '" + path + "': " + ex));
} }
return;
}
if (onSuccess) {
onSuccess();
} }
} }
@ -313,7 +284,7 @@ export class FileSystemAccess {
return ""; return "";
} }
private deleteEntity(path: string, onSuccess?: () => any, onError?: (error: any) => any) { private deleteEntity(path: string, onError?: (error: any) => any) {
var fileManager = NSFileManager.defaultManager(); var fileManager = NSFileManager.defaultManager();
try { try {
fileManager.removeItemAtPathError(path); fileManager.removeItemAtPathError(path);
@ -323,10 +294,6 @@ export class FileSystemAccess {
onError(new Error("Failed to delete file at path '" + path + "': " + ex)); onError(new Error("Failed to delete file at path '" + path + "': " + ex));
} }
} }
if (onSuccess) {
onSuccess();
}
} }
private enumEntities(path: string, callback: (entity: { path: string; name: string; extension: string }) => boolean, onError?: (error) => any) { private enumEntities(path: string, callback: (entity: { path: string; name: string; extension: string }) => boolean, onError?: (error) => any) {

View File

@ -7,134 +7,172 @@ declare module "file-system" {
* Represents a single entity on the file system. * Represents a single entity on the file system.
*/ */
export class FileSystemEntity { export class FileSystemEntity {
/** /**
* Gets the Date object specifying the last time this entity was modified. * Gets the Date object specifying the last time this entity was modified.
*/ */
lastModified: Date; lastModified: Date;
/** /**
* Gets the name of the entity. * Gets the name of the entity.
*/ */
name: string; name: string;
/** /**
* Gets the fully-qualified path (including the extension for a File) of the entity. * Gets the fully-qualified path (including the extension for a File) of the entity.
*/ */
path: string; path: string;
/** /**
* Gets the Folder object representing the parent of this entity. * Gets the Folder object representing the parent of this entity.
* Will be null for a root folder like Documents or Temporary. * Will be null for a root folder like Documents or Temporary.
* This property is readonly. * This property is readonly.
*/ */
parent: Folder; parent: Folder;
/** /**
* Removes (deletes) the current Entity from the file system. * Removes (deletes) the current Entity from the file system.
*/ */
remove(): Promise<any>; remove(): Promise<any>;
/** /**
* Renames the current entity using the specified name. * Removes (deletes) the current Entity from the file system synchronously.
* @param newName The new name to be applied to the entity. */
*/ removeSync(onError?: (error: any) => any): void;
/**
* Renames the current entity using the specified name.
* @param newName The new name to be applied to the entity.
*/
rename(newName: string): Promise<any>; rename(newName: string): Promise<any>;
/**
* Renames the current entity synchronously, using the specified name.
* @param newName The new name to be applied to the entity.
*/
renameSync(newName: string, onError?: (error: any) => any): void;
} }
/** /**
* Represents a File entity on the file system. * Represents a File entity on the file system.
*/ */
export class File extends FileSystemEntity { export class File extends FileSystemEntity {
/** /**
* Checks whether a File with the specified path already exists. * Checks whether a File with the specified path already exists.
* @param path The path to check for. * @param path The path to check for.
*/ */
static exists(path: string): boolean; static exists(path: string): boolean;
/** /**
* Gets the extension of the file. * Gets the extension of the file.
*/ */
extension: string; extension: string;
/** /**
* Gets a value indicating whether the file is currently locked, meaning a background operation associated with this file is running. * Gets a value indicating whether the file is currently locked, meaning a background operation associated with this file is running.
*/ */
isLocked: boolean; isLocked: boolean;
/** /**
* Gets or creates a File entity at the specified path. * Gets or creates a File entity at the specified path.
* @param path The path to get/create the file at. * @param path The path to get/create the file at.
*/ */
static fromPath(path: string): File; static fromPath(path: string): File;
/** /**
* Reads the content of the file as a string using the specified encoding (defaults to UTF-8). * Reads the content of the file as a string using the specified encoding (defaults to UTF-8).
* @param encoding An optional value specifying the preferred encoding (defaults to UTF-8). * @param encoding An optional value specifying the preferred encoding (defaults to UTF-8).
*/ */
readText(encoding?: string): Promise<string>; readText(encoding?: string): Promise<string>;
/** /**
* Writes the provided string to the file, using the specified encoding (defaults to UTF-8). * Reads the content of the file as a string synchronously, using the specified encoding (defaults to UTF-8).
* @param content The content to be saved to the file. * @param onError An optional function to be called if some IO-error occurs.
* @param encoding An optional value specifying the preferred encoding (defaults to UTF-8). * @param encoding An optional value specifying the preferred encoding (defaults to UTF-8).
*/ */
readTextSync(onError?: (error: any) => any, encoding?: string): string;
/**
* Writes the provided string to the file, using the specified encoding (defaults to UTF-8).
* @param content The content to be saved to the file.
* @param encoding An optional value specifying the preferred encoding (defaults to UTF-8).
*/
writeText(content: string, encoding?: string): Promise<any>; writeText(content: string, encoding?: string): Promise<any>;
/**
* Writes the provided string to the file synchronously, using the specified encoding (defaults to UTF-8).
* @param content The content to be saved to the file.
* @param onError An optional function to be called if some IO-error occurs.
* @param encoding An optional value specifying the preferred encoding (defaults to UTF-8).
*/
writeTextSync(content: string, onError?: (error: any) => any, encoding?: string): void;
} }
/** /**
* Represents a Folder (directory) entity on the file system. * Represents a Folder (directory) entity on the file system.
*/ */
export class Folder extends FileSystemEntity { export class Folder extends FileSystemEntity {
/** /**
* Determines whether this instance is a KnownFolder (accessed through the KnownFolders object). * Determines whether this instance is a KnownFolder (accessed through the KnownFolders object).
*/ */
isKnown: boolean; isKnown: boolean;
/** /**
* Gets or creates a Folder entity at the specified path. * Gets or creates a Folder entity at the specified path.
* @param path The path to get/create the folder at. * @param path The path to get/create the folder at.
*/ */
static fromPath(path: string): Folder; static fromPath(path: string): Folder;
/** /**
* Checks whether a Folder with the specified path already exists. * Checks whether a Folder with the specified path already exists.
* @param path The path to check for. * @param path The path to check for.
*/ */
static exists(path: string): boolean; static exists(path: string): boolean;
/** /**
* Checks whether this Folder contains an Entity with the specified name. * Checks whether this Folder contains an Entity with the specified name.
* The path of the folder is added to the name to resolve the complete path to check for. * The path of the folder is added to the name to resolve the complete path to check for.
* @param name The name of the entity to check for. * @param name The name of the entity to check for.
*/ */
contains(name: string): boolean; contains(name: string): boolean;
/** /**
* Deletes all the files and folders (recursively), contained within this Folder. * Deletes all the files and folders (recursively), contained within this Folder.
*/ */
clear(): Promise<any>; clear(): Promise<any>;
/** /**
* Gets or creates a File entity with the specified name within this Folder. * Deletes all the files and folders (recursively), contained within this Folder synchronously.
* @param name The name of the file to get/create. * @param onError An optional function to be called if some error occurs.
*/ */
clearSync(onError?: (error: any) => void): void;
/**
* Gets or creates a File entity with the specified name within this Folder.
* @param name The name of the file to get/create.
*/
getFile(name: string): File; getFile(name: string): File;
/** /**
* Gets or creates a Folder entity with the specified name within this Folder. * Gets or creates a Folder entity with the specified name within this Folder.
* @param name The name of the folder to get/create. * @param name The name of the folder to get/create.
*/ */
getFolder(name: string): Folder; getFolder(name: string): Folder;
/** /**
* Gets all the top-level entities residing within this folder. * Gets all the top-level entities residing within this folder.
*/ */
getEntities(): Promise<Array<FileSystemEntity>>; getEntities(): Promise<Array<FileSystemEntity>>;
/** /**
* Enumerates all the top-level FileSystem entities residing within this folder. * Gets all the top-level entities residing within this folder synchronously.
* @param onEntity A callback that receives the current entity. If the callback returns false this will mean for the iteration to stop. * @param onError An optional function to be called if some error occurs.
*/ */
getEntitiesSync(onError?: (error: any) => any): Promise<Array<FileSystemEntity>>;
/**
* Enumerates all the top-level FileSystem entities residing within this folder.
* @param onEntity A callback that receives the current entity. If the callback returns false this will mean for the iteration to stop.
*/
eachEntity(onEntity: (entity: FileSystemEntity) => boolean); eachEntity(onEntity: (entity: FileSystemEntity) => boolean);
} }

View File

@ -63,60 +63,91 @@ export class FileSystemEntity {
public remove(): Promise<any> { public remove(): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var fileAccess = getFileAccess(); var hasError = false;
var localSucces = function () {
resolve();
};
var localError = function (error: any) { var localError = function (error: any) {
hasError = true;
reject(error); reject(error);
}; };
if (this instanceof File) { this.removeSync(localError);
fileAccess.deleteFile(this.path, localSucces, localError); if (!hasError) {
} else if (this instanceof Folder) { resolve();
fileAccess.deleteFolder(this.path, this[isKnownProperty], localSucces, localError);
} }
}); });
} }
public removeSync(onError?: (error: any) => any): void {
if (this[isKnownProperty]) {
if (onError) {
onError({ message: "Cannot delete known folder." });
}
return;
}
var fileAccess = getFileAccess();
if (this instanceof File) {
fileAccess.deleteFile(this.path, onError);
} else if (this instanceof Folder) {
fileAccess.deleteFolder(this.path, onError);
}
}
public rename(newName: string): Promise<any> { public rename(newName: string): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
if (this instanceof Folder) { var hasError = false;
if (this[isKnownProperty]) {
reject(new Error("Cannot rename known folder."));
}
}
var parentFolder = this.parent;
if (!parentFolder) {
reject(new Error("No parent folder."));
}
var fileAccess = getFileAccess();
var path = parentFolder.path;
var newPath = fileAccess.joinPath(path, newName);
var localSucceess = () => {
this[pathProperty] = newPath;
this[nameProperty] = newName;
if (this instanceof File) {
this[extensionProperty] = fileAccess.getFileExtension(newPath);
}
resolve();
}
var localError = function (error) { var localError = function (error) {
hasError = true;
reject(error); reject(error);
} }
fileAccess.rename(this.path, newPath, localSucceess, localError); this.renameSync(newName, localError);
if (!hasError) {
resolve();
}
}); });
} }
public renameSync(newName: string, onError?: (error: any) => any): void {
if (this[isKnownProperty]) {
if (onError) {
onError(new Error("Cannot rename known folder."));
}
return;
}
var parentFolder = this.parent;
if (!parentFolder) {
if (onError) {
onError(new Error("No parent folder."));
}
return;
}
var fileAccess = getFileAccess();
var path = parentFolder.path;
var newPath = fileAccess.joinPath(path, newName);
var hasError = false;
var localError = function (error) {
hasError = true;
if (onError) {
onError(error);
}
return null;
}
fileAccess.rename(this.path, newPath, localError);
this[pathProperty] = newPath;
this[nameProperty] = newName;
if (this instanceof File) {
this[extensionProperty] = fileAccess.getFileExtension(newPath);
}
}
get name(): string { get name(): string {
return this[nameProperty]; return this[nameProperty];
} }
@ -136,7 +167,6 @@ export class FileSystemEntity {
} }
export class File extends FileSystemEntity { export class File extends FileSystemEntity {
public static fromPath(path: string) { public static fromPath(path: string) {
var onError = function (error) { var onError = function (error) {
throw error; throw error;
@ -164,50 +194,71 @@ export class File extends FileSystemEntity {
} }
public readText(encoding?: string): Promise<string> { public readText(encoding?: string): Promise<string> {
this.checkAccess();
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this[fileLockedProperty] = true; var hasError = false;
var localSuccess = (content: string) => {
this[fileLockedProperty] = false;
resolve(content);
};
var localError = (error) => { var localError = (error) => {
this[fileLockedProperty] = false; hasError = true;
reject(error); reject(error);
}; };
// TODO: Asyncronous var content = this.readTextSync(localError, encoding);
getFileAccess().readText(this.path, localSuccess, localError, encoding); if (!hasError) {
resolve(content);
}
}); });
} }
public writeText(content: string, encoding?: string): Promise<any> { public readTextSync(onError?: (error: any) => any, encoding?: string): string {
this.checkAccess(); this.checkAccess();
this[fileLockedProperty] = true;
var that = this;
var localError = (error) => {
that[fileLockedProperty] = false;
if (onError) {
onError(error);
}
};
var content = getFileAccess().readText(this.path, localError, encoding);
this[fileLockedProperty] = false;
return content;
}
public writeText(content: string, encoding?: string): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
this[fileLockedProperty] = true; var hasError = false;
var that = this;
var localSuccess = function () {
that[fileLockedProperty] = false;
resolve();
};
var localError = function (error) { var localError = function (error) {
that[fileLockedProperty] = false; hasError = true;
reject(error); reject(error);
}; };
// TODO: Asyncronous this.writeTextSync(content, localError, encoding);
getFileAccess().writeText(this.path, content, localSuccess, localError, encoding); if (!hasError) {
resolve();
}
}); });
} }
public writeTextSync(content: string, onError?: (error: any) => any, encoding?: string): void {
this.checkAccess();
this[fileLockedProperty] = true;
var that = this;
var localError = function (error) {
that[fileLockedProperty] = false;
if (onError) {
onError(error);
}
};
// TODO: Asyncronous
getFileAccess().writeText(this.path, content, localError, encoding);
}
private checkAccess() { private checkAccess() {
if (this.isLocked) { if (this.isLocked) {
throw new Error("Cannot access a locked file."); throw new Error("Cannot access a locked file.");
@ -216,7 +267,6 @@ export class File extends FileSystemEntity {
} }
export class Folder extends FileSystemEntity { export class Folder extends FileSystemEntity {
public static fromPath(path: string): Folder { public static fromPath(path: string): Folder {
var onError = function (error) { var onError = function (error) {
throw error; throw error;
@ -247,20 +297,23 @@ export class Folder extends FileSystemEntity {
public clear(): Promise<any> { public clear(): Promise<any> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var hasError = false;
var onSuccess = function () {
resolve();
};
var onError = function (error) { var onError = function (error) {
hasError = true;
reject(error); reject(error);
}; };
getFileAccess().emptyFolder(this.path, onSuccess, onError); this.clearSync(onError);
if (!hasError) {
resolve();
}
}); });
} }
public clearSync(onError?: (error: any) => void): void {
getFileAccess().emptyFolder(this.path, onError);
}
get isKnown(): boolean { get isKnown(): boolean {
return this[isKnownProperty]; return this[isKnownProperty];
} }
@ -299,31 +352,39 @@ export class Folder extends FileSystemEntity {
public getEntities(): Promise<Array<FileSystemEntity>> { public getEntities(): Promise<Array<FileSystemEntity>> {
return new Promise((resolve, reject) => { return new Promise((resolve, reject) => {
var hasError = false;
var onSuccess = function (fileInfos: Array<{ path: string; name: string; extension: string }>) { var localError = function (error) {
var entities = new Array<FileSystemEntity>(); hasError = true;
var i; reject(error);
for (i = 0; i < fileInfos.length; i++) {
if (fileInfos[i].extension) {
entities.push(createFile(fileInfos[i]));
} else {
entities.push(createFolder(fileInfos[i]));
}
}
resolve(entities);
}
var onError = function (error) {
throw error;
}; };
getFileAccess().getEntities(this.path, onSuccess, onError); var entities = this.getEntitiesSync(localError);
if (!hasError) {
resolve(entities);
}
}); });
} }
public getEntitiesSync(onError?: (error: any) => any): Array<FileSystemEntity> {
var fileInfos = getFileAccess().getEntities(this.path, onError);
if (!fileInfos) {
return null;
}
var entities = new Array<FileSystemEntity>();
var i;
for (i = 0; i < fileInfos.length; i++) {
if (fileInfos[i].extension) {
entities.push(createFile(fileInfos[i]));
} else {
entities.push(createFolder(fileInfos[i]));
}
}
return entities;
}
public eachEntity(onEntity: (entity: FileSystemEntity) => boolean) { public eachEntity(onEntity: (entity: FileSystemEntity) => boolean) {
if (!onEntity) { if (!onEntity) {
return; return;

View File

@ -1,7 +1,6 @@
import view = require("ui/core/view"); import view = require("ui/core/view");
import fs = require("file-system"); import fs = require("file-system");
import xml = require("xml"); import xml = require("xml");
import file_access_module = require("file-system/file-system-access");
import types = require("utils/types"); import types = require("utils/types");
import componentBuilder = require("ui/builder/component-builder"); import componentBuilder = require("ui/builder/component-builder");
import templateBuilderDef = require("ui/builder/template-builder"); import templateBuilderDef = require("ui/builder/template-builder");
@ -261,15 +260,12 @@ function loadInternal(fileName: string, context?: any): componentBuilder.Compone
// Check if the XML file exists. // Check if the XML file exists.
if (fs.File.exists(fileName)) { if (fs.File.exists(fileName)) {
var file = fs.File.fromPath(fileName);
var fileAccess = new file_access_module.FileSystemAccess(); var onError = function (error) {
throw new Error("Error loading file " + fileName + " :" + error.message);
// Read the XML file. }
fileAccess.readText(fileName, result => { var text = file.readTextSync(onError);
componentModule = parseInternal(result, context); componentModule = parseInternal(text, context);
}, (e) => {
throw new Error("Error loading file " + fileName + " :" + e.message);
});
} }
if (componentModule && componentModule.component) { if (componentModule && componentModule.component) {

View File

@ -5,7 +5,6 @@ import frame = require("ui/frame");
import styleModule = require("ui/styling/style"); import styleModule = require("ui/styling/style");
import styleScope = require("ui/styling/style-scope"); import styleScope = require("ui/styling/style-scope");
import fs = require("file-system"); import fs = require("file-system");
import fileSystemAccess = require("file-system/file-system-access");
import frameCommon = require("ui/frame/frame-common"); import frameCommon = require("ui/frame/frame-common");
import actionBar = require("ui/action-bar"); import actionBar = require("ui/action-bar");
import dependencyObservable = require("ui/core/dependency-observable"); import dependencyObservable = require("ui/core/dependency-observable");
@ -131,10 +130,12 @@ export class Page extends contentView.ContentView implements dts.Page {
} }
if (!this._cssFiles[cssFileName]) { if (!this._cssFiles[cssFileName]) {
if (fs.File.exists(cssFileName)) { if (fs.File.exists(cssFileName)) {
new fileSystemAccess.FileSystemAccess().readText(cssFileName, r => { var file = fs.File.fromPath(cssFileName);
var text = file.readTextSync();
if (text) {
this._addCssInternal(r, cssFileName); this._addCssInternal(r, cssFileName);
this._cssFiles[cssFileName] = true; this._cssFiles[cssFileName] = true;
}); }
} }
} }
} }

View File

@ -7,9 +7,7 @@ import application = require("application");
import utils = require("utils/utils"); import utils = require("utils/utils");
import types = require("utils/types"); import types = require("utils/types");
import fs = require("file-system"); import fs = require("file-system");
import file_access_module = require("file-system/file-system-access");
var fileAccess = new file_access_module.FileSystemAccess();
var pattern: RegExp = /url\(('|")(.*?)\1\)/; var pattern: RegExp = /url\(('|")(.*?)\1\)/;
export class StyleScope { export class StyleScope {
@ -89,9 +87,13 @@ export class StyleScope {
fileName = fs.path.join(fs.knownFolders.currentApp().path, fileName.replace("~/", "")); fileName = fs.path.join(fs.knownFolders.currentApp().path, fileName.replace("~/", ""));
} }
fileAccess.readText(fileName, result => { if (fs.File.exists(fileName)) {
selectors = StyleScope._joinCssSelectorsArrays([selectors, StyleScope.createSelectorsFromCss(result, fileName)]); var file = fs.File.fromPath(fileName);
}); var text = file.readTextSync();
if (text) {
selectors = StyleScope._joinCssSelectorsArrays([selectors, StyleScope.createSelectorsFromCss(text, fileName)]);
}
}
} }
} }
} }