// Copyright (c) Microsoft Corporation. All rights reserved. // Licensed under the MIT license. using System; using System.IO; using System.Threading; using Microsoft.ClearScript.JavaScript; using Microsoft.ClearScript.Util; namespace Microsoft.ClearScript { /// /// Contains meta-information for a document. /// public struct DocumentInfo { private static long lastUniqueId; private readonly string name; private DocumentCategory category; private ulong uniqueId; /// /// Initializes a new structure with the specified document name. /// /// The document name. public DocumentInfo(string name) : this() { this.name = name; uniqueId = Interlocked.Increment(ref lastUniqueId).ToUnsigned(); } /// /// Initializes a new structure with the specified document URI. /// /// The document URI. public DocumentInfo(Uri uri) : this() { MiscHelpers.VerifyNonNullArgument(uri, nameof(uri)); Uri = uri.IsAbsoluteUri ? uri : new Uri(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + uri); name = Path.GetFileName(Uri.AbsolutePath); uniqueId = Interlocked.Increment(ref lastUniqueId).ToUnsigned(); } /// /// Gets the document's name. /// /// /// This property always returns a non-blank string. If a null or blank document name was /// specified at instantiation time, this property returns a default document name. /// public string Name => MiscHelpers.EnsureNonBlank(name, Category.DefaultName); /// /// Gets the document's URI. /// /// /// This property returns null if a URI was not specified at instantiation time. /// public Uri Uri { get; } /// /// Gets or sets an optional source map URI for the document. /// public Uri SourceMapUri { get; set; } /// /// Gets or sets the document's category. /// public DocumentCategory Category { get => category ?? DocumentCategory.Script; set => category = value; } /// /// Gets or sets optional document attributes. /// public DocumentFlags? Flags { get; set; } /// /// Gets or sets an optional context callback for the document. /// /// /// /// This property currently applies only to modules. If specified, the callback is invoked /// the first time the module attempts to retrieve its context information. The properties /// it returns are made available to the module implementation. This mechanism can be used /// to expose host resources selectively, securely, and without polluting the script /// engine's global namespace. /// /// /// Use /// import.meta /// to access the context information of a JavaScript /// module. In a module, use module.meta. /// /// public DocumentContextCallback ContextCallback { get; set; } internal UniqueDocumentInfo MakeUnique(ScriptEngine engine) { return MakeUnique(engine.DocumentNameManager); } internal UniqueDocumentInfo MakeUnique(ScriptEngine engine, DocumentFlags? defaultFlags) { return MakeUnique(engine.DocumentNameManager, defaultFlags); } internal UniqueDocumentInfo MakeUnique(IUniqueNameManager manager) { return MakeUnique(manager, null); } internal UniqueDocumentInfo MakeUnique(IUniqueNameManager manager, DocumentFlags? defaultFlags) { var info = this; if (!info.Flags.HasValue && defaultFlags.HasValue) { info.Flags = defaultFlags; } if (uniqueId < 1) { uniqueId = Interlocked.Increment(ref lastUniqueId).ToUnsigned(); } var uniqueName = manager.GetUniqueName(Name, Category.DefaultName); if (info.Flags.GetValueOrDefault().HasFlag(DocumentFlags.IsTransient)) { uniqueName += " [temp]"; } return new UniqueDocumentInfo(info, uniqueId, uniqueName); } } }