Skip to content

Commit

Permalink
Fix #1397: import modules beginning with a number
Browse files Browse the repository at this point in the history
  • Loading branch information
alfonsogarciacaro committed May 4, 2018
1 parent 76c0889 commit a1a2edd
Show file tree
Hide file tree
Showing 5 changed files with 32 additions and 18 deletions.
30 changes: 22 additions & 8 deletions src/dotnet/Fable.Core/Util.fs
Expand Up @@ -103,27 +103,41 @@ module Naming =
let umdModules =
set ["commonjs"; "amd"; "umd"]

let isIdentChar c = System.Char.IsLetterOrDigit (c) || c = '_'
// Dollar sign is reserved by Fable as a special character
// to encode other characters, unique var names and as a separator
let isIdentChar i (c: char) =
let code = int c
c = '_'
|| (65 <= code && code <= 90) // a-z
|| (97 <= code && code <= 122) // A-Z
// Digits are not allowed in first position, see #1397
|| (i > 0 && 48 <= code && code <= 57) // 0-9

let hasIdentForbiddenChars (ident: string) =
let mutable i = 0
while i < ident.Length && (isIdentChar ident.[i]) do i <- i + 1
while i < ident.Length && (isIdentChar i ident.[i]) do i <- i + 1
i < ident.Length

let replaceIdentForbiddenChars (ident: string) =
System.String.Concat(seq {
for c in ident ->
if isIdentChar c then string c
else sprintf "$%X$" (int c)
for i = 0 to (ident.Length - 1) do
let c = ident.[i]
if isIdentChar i c
then yield string c
else yield sprintf "$%X$" (int c)
})

let sanitizeIdentForbiddenChars (ident: string) =
System.String(
[| for c in ident -> if isIdentChar c then c else '_' |] )
[| for i = 0 to (ident.Length - 1) do
let c = ident.[i]
if isIdentChar i c
then yield c else
yield '_' |] )

let hasGenericPlaceholder (ident: string) =
let i = ident.IndexOf(@"\$'")
i >= 0 && i + 2 < ident.Length && (isIdentChar ident.[i + 2])
i >= 0 && i + 2 < ident.Length && (isIdentChar (i + 2) ident.[i + 2])

let replacePattern (prefix: string) (cond: char->bool) (repl: string->string) (str: string) =
let rec replace (acc: string) (s: string) =
Expand All @@ -138,7 +152,7 @@ module Naming =
replace "" str

let replaceGenericPlaceholder (ident: string, onMatch: string -> string) =
replacePattern @"\$'" isIdentChar onMatch ident
replacePattern @"\$'" (isIdentChar 1) onMatch ident

let replaceGenericArgsCount (ident: string, replacement: string) =
replacePattern @"`" System.Char.IsDigit (fun _ -> replacement) ident
Expand Down
12 changes: 6 additions & 6 deletions tests/Main/ImportTests.fs
Expand Up @@ -10,13 +10,13 @@ type IFooImported =
abstract foo: string

#if FABLE_COMPILER
[<Fable.Core.Import("*", "./js/foo.js")>]
[<Fable.Core.Import("*", "./js/1foo.js")>]
let fooAll: IFooImported = failwith "JS only"

[<Test>]
let ``Import with relative paths works``() =
fooAll.foo |> equal "foo"
let fooAll2: IFooImported = Fable.Core.JsInterop.importAll "./js/foo.js"
let fooAll2: IFooImported = Fable.Core.JsInterop.importAll "./js/1foo.js"
fooAll2.foo |> equal "foo"

[<Test>]
Expand Down Expand Up @@ -99,7 +99,7 @@ let ``Identifiers are encoded correctly``() = // See #482
#if FABLE_COMPILER
open Fable.Core

[<Import("MyClass", "./js/foo.js")>]
[<Import("MyClass", "./js/1foo.js")>]
type MyClass() =
new (v: string) = MyClass()
member x.value: string = jsNative
Expand Down Expand Up @@ -130,7 +130,7 @@ type FooOptional =

[<Test>]
let ``Only omitted optional arguments are removed``() = // See #231, #640
let x: FooOptional = Fable.Core.JsInterop.import "fooOptional" "./js/foo.js"
let x: FooOptional = Fable.Core.JsInterop.import "fooOptional" "./js/1foo.js"
x.Foo1(5) |> equal 1
x.Foo1(5, "3") |> equal 2
x.Foo2(5, None) |> equal 2
Expand All @@ -139,12 +139,12 @@ let ``Only omitted optional arguments are removed``() = // See #231, #640
x.Foo2(5,Some "3") |> equal 2
x.Foo3(5, "3") |> equal 2

let square : int -> int = JsInterop.importMember "./js/foo.js"
let square : int -> int = JsInterop.importMember "./js/1foo.js"
[<Test>]
let ``Importing curried functions via `importMember` without naming arguments works`` () = // See #1185
square 2 |> equal 4

let add : int -> int -> int = JsInterop.importMember "./js/foo.js"
let add : int -> int -> int = JsInterop.importMember "./js/1foo.js"
[<Test>]
let ``Importing curried functions with multiple arguments via `importMember` without naming arguments works`` () =
add 40 2 |> equal 42
Expand Down
6 changes: 3 additions & 3 deletions tests/Main/Util/Util.fs
Expand Up @@ -16,12 +16,12 @@ module Testing =
open Testing

#if FABLE_COMPILER
let foo: string = Fable.Core.JsInterop.importMember "../js/foo.js"
let foo: string = Fable.Core.JsInterop.importMember "../js/1foo.js"

[<Fable.Core.Import("foo", "../js/foo.js")>]
[<Fable.Core.Import("foo", "../js/1foo.js")>]
let foo2: string = failwith "JS only"

let apply (f:Func<int,int,int>) (x:int) (y:int) = Fable.Core.JsInterop.importMember "../js/foo.js"
let apply (f:Func<int,int,int>) (x:int) (y:int) = Fable.Core.JsInterop.importMember "../js/1foo.js"
#else
let foo = "foo"
let foo2 = "foo"
Expand Down
File renamed without changes.
2 changes: 1 addition & 1 deletion tests_external/Util4.fs
Expand Up @@ -3,7 +3,7 @@ module Fable.Tests.Util4
open Fable.Core

#if FABLE_COMPILER
let foo: string = JsInterop.importMember "../tests/Main/js/foo.js"
let foo: string = JsInterop.importMember "../tests/Main/js/1foo.js"

let bar: int = JsInterop.importMember "./bar.js"

Expand Down

0 comments on commit a1a2edd

Please sign in to comment.