diff --git a/js/js.libraries/src/core/annotations.kt b/js/js.libraries/src/core/annotations.kt index e06d873a4e5..7894162f868 100644 --- a/js/js.libraries/src/core/annotations.kt +++ b/js/js.libraries/src/core/annotations.kt @@ -40,18 +40,138 @@ internal annotation class library(public val name: String = "") @Target(CLASS) internal annotation class marker +/** + * Gives a declaration (a function, a property or a class) specific name in JavaScript. + * + * This may be useful in the following cases: + * + * * There are two functions for which the compiler gives same name in JavaScript, you can + * mark one with `@JsName(...)` to prevent the compiler from reporting error. + * * You are writing a JavaScript library in Kotlin. The compiler produces mangled names + * for functions with parameters, which is unnatural for usual JavaScript developer. + * You can put `@JsName(...)` on functions you want to be available from JavaScript. + * * For some reason you want to rename declaration, e.g. there's common term in JavaScript + * for a concept provided by the declaration, which in uncommon in Kotlin. + * + * Example: + * + * ``` kotlin + * class Person(val name: String) { + * fun hello() { + * println("Hello $name!") + * } + * + * @JsName("helloWithGreeting") + * fun hello(greeting: String) { + * println("$greeting $name!") + * } + * } + * ``` + * + * @property name the name which compiler uses both for declaration itself and for all references to the declaration. + * It's required to denote a valid JavaScript identifier. + * + * @since 1.1 + */ @Retention(AnnotationRetention.BINARY) @Target(CLASS, FUNCTION, PROPERTY, CONSTRUCTOR, PROPERTY_GETTER, PROPERTY_SETTER) annotation class JsName(val name: String) +/** + * Denotes an `external` declaration that must be imported from native JavaScript library. + * + * The compiler produces the code relevant for the target module system, for example, in case of CommonJS, + * it will import the declaration via the `require(...)` function. + * + * The annotation can be used on top-level external declarations (classes, properties, functions) and files. + * In case of file (which can't be `external`) the following rule applies: all the declarations in + * the file must be `external`. By applying `@JsModule(...)` on a file you tell the compiler to import a JavaScript object + * that contain all the declarations from the file. + * + * Example: + * + * ``` kotlin + * @JsModule("jquery") + * external abstract class JQuery() { + * // some declarations here + * } + * + * @JsModule("jquery") + * external fun JQuery(element: Element): JQuery + * ``` + * + * @property import name of a module to import declaration from. + * It is not interpreted by the Kotlin compiler, it's passed as is directly to the target module system. + * + * @see JsNonModule + * @since 1.1 + */ @Retention(AnnotationRetention.BINARY) @Target(CLASS, PROPERTY, FUNCTION, FILE) annotation class JsModule(val import: String) +/** + * Denotes an `external` declaration that can be used without module system. + * + * By default, an `external` declaration is available regardless your target module system. + * However, by applying [JsModule] annotation you can make a declaration unavailable to *plain* module system. + * Some JavaScript libraries are distributed both as a standalone downloadable piece of JavaScript and as a module available + * as an npm package. + * To tell the Kotlin compiler to accept both cases, you can augment [JsModule] with the `@JsNonModule` annotation. + * + * For example: + * + * ``` kotlin + * @JsModule("jquery") + * @JsNonModule + * @JsName("$") + * external abstract class JQuery() { + * // some declarations here + * } + * + * @JsModule("jquery") + * @JsNonModule + * @JsName("$") + * external fun JQuery(element: Element): JQuery + * ``` + * + * @see JsModule + * @since 1.1 + */ @Retention(AnnotationRetention.BINARY) @Target(CLASS, PROPERTY, FUNCTION, FILE) annotation class JsNonModule +/** + * Adds prefix to `external` declarations in a source file. + * + * JavaScript does not have concept of packages (namespaces). They are usually emulated by nested objects. + * The compiler turns references to `external` declarations either to plain unprefixed names (in case of *plain* modules) + * or to plain imports. + * However, if a JavaScript library provides its declarations in packages, you won't be satisfied with this. + * You can tell the compiler to generate additional prefix before references to `external` declarations using the `@JsQuafier(...)` + * annotation. + * + * Note that a file marked with the `@JsQulifier(...)` annotation can't contain non-`external` declarations. + * + * Example: + * + * ``` + * @file:JsQualifier("my.jsPackageName") + * package some.kotlinPackage + * + * external fun foo(x: Int) + * + * external fun bar(): String + * ``` + * + * @property value the qualifier to add to the declarations in the generated code. + * It must be a sequence of valid JavaScript identifiers separated by the `.` character. + * Examples of valid qualifiers are: `foo`, `bar.Baz`, `_.$0.f`. + * + * @see JsModule + * @since 1.1 + */ @Retention(AnnotationRetention.BINARY) @Target(AnnotationTarget.FILE) annotation class JsQualifier(val value: String) \ No newline at end of file diff --git a/js/js.libraries/src/core/core.kt b/js/js.libraries/src/core/core.kt index 88e0474cf24..08ca98e7ab6 100644 --- a/js/js.libraries/src/core/core.kt +++ b/js/js.libraries/src/core/core.kt @@ -3,6 +3,32 @@ package kotlin.js @Deprecated(message = "Use `definedExternally` instead", level = DeprecationLevel.ERROR, replaceWith = ReplaceWith("definedExternally")) public external val noImpl: Nothing +/** + * The property that can be used as a placeholder for statements and values that are defined in JavaScript. + * + * This property can be used in two cases: + * + * * To represent body of an external function. In most cases Kotlin does not require to provide bodies of external + * functions and properties, but if for some reason you want to (for example, due to limitation of your coding style guides), + * you should use `definedExternally`. + * * To represent value of default argument. + * + * There's two forms of using `definedExternally`: + * + * 1. `= definedExternally` (for functions, properties and parameters). + * 2. `{ definedExternally }` (for functions and property getters/setters). + * + * This property can't be used from normal code. + * + * Examples: + * + * ``` kotlin + * external fun foo(): String = definedExternally + * external fun bar(x: Int) { definedExternally } + * external fun baz(z: Any = definedExternally): Array + * external val prop: Float = definedExternally + * ``` + */ public external val definedExternally: Nothing /** @@ -24,6 +50,23 @@ public external fun parseInt(s: String, radix: Int = definedExternally): Int @Deprecated("Use toDouble() instead.", ReplaceWith("s.toDouble()"), level = DeprecationLevel.ERROR) public external fun parseFloat(s: String, radix: Int = definedExternally): Double +/** + * Puts the given piece of a JavaScript code right into the calling function. + * The compiler replaces call to `js(...)` code with the string constant provided as a parameter. + * + * Example: + * + * ``` kotlin + * fun logToConsole(message: String): Unit { + * js("console.log(message)") + * } + * ``` + * + * @param code the piece of JavaScript code to put to the generated code. + * Must be a compile-time constant, otherwise compiler produces error message. + * You can safely refer to local variables of calling function (but not to local variables of outer functions), + * including parameters. You can't refer to functions, properties and classes by their short names. + */ public external fun js(code: String): dynamic /**