mirror of
https://github.com/wasp-lang/wasp.git
synced 2024-12-25 18:13:52 +03:00
Implemented basic importing of wasp code from external code.
This commit is contained in:
parent
c8c7e0a1e4
commit
17a82848df
28
examples/todoMVC/src/Todo.jsx
Normal file
28
examples/todoMVC/src/Todo.jsx
Normal file
@ -0,0 +1,28 @@
|
||||
import React from 'react'
|
||||
|
||||
import NewTaskForm from '@wasp/entities/task/components/NewTaskForm'
|
||||
import TaskList from '@wasp/entities/task/components/List'
|
||||
|
||||
import * as config from './config'
|
||||
|
||||
|
||||
export default class Todo extends React.Component {
|
||||
render = () => {
|
||||
return <div className="mainContainer">
|
||||
<h1> { config.appName } </h1>
|
||||
|
||||
<NewTaskForm
|
||||
onCreate={task => this.props.addTask(task)}
|
||||
submitButtonLabel={'Create new task'}
|
||||
/>
|
||||
|
||||
<div className="taskListContainer">
|
||||
<TaskList editable />
|
||||
</div>
|
||||
|
||||
<div className="footer">
|
||||
{ this.props.taskList.filter(task => !task.isDone).length } items left
|
||||
</div>
|
||||
</div>
|
||||
}
|
||||
}
|
@ -1,4 +0,0 @@
|
||||
|
||||
export const hello = () => {
|
||||
return "Hello!"
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
// Goal of this file is to re-create a TODO app from http://todomvc.com
|
||||
|
||||
import * as config from "config" // Imports from external code dir (src/).
|
||||
import Todo from "Todo" // Imports from external code dir (src/).
|
||||
|
||||
// -- Entities
|
||||
entity Task {
|
||||
@ -34,22 +34,10 @@ page Main {
|
||||
css=},
|
||||
|
||||
content: {=jsx
|
||||
<div className="mainContainer">
|
||||
<h1> { config.appName } </h1>
|
||||
|
||||
<NewTaskForm
|
||||
onCreate={task => this.props.addTask(task)}
|
||||
submitButtonLabel={'Create new task'}
|
||||
/>
|
||||
|
||||
<div className="taskListContainer">
|
||||
<TaskList editable />
|
||||
</div>
|
||||
|
||||
<div className="footer">
|
||||
{ this.props.taskList.filter(task => !task.isDone).length } items left
|
||||
</div>
|
||||
</div>
|
||||
<Todo
|
||||
addTask={this.props.addTask}
|
||||
taskList={this.props.taskList}>
|
||||
</Todo>
|
||||
jsx=}
|
||||
}
|
||||
|
||||
|
@ -50,6 +50,7 @@ library:
|
||||
- split
|
||||
- unordered-containers
|
||||
- path
|
||||
- regex-compat
|
||||
|
||||
executables:
|
||||
stic-exe:
|
||||
|
@ -1,48 +1,30 @@
|
||||
module Generator.ExternalCode
|
||||
( generateExternalCodeDir
|
||||
, externalCodeDirPathInSrc
|
||||
) where
|
||||
|
||||
import System.FilePath (takeExtension)
|
||||
import qualified System.FilePath as FP
|
||||
import qualified Path
|
||||
import Path ((</>), reldir)
|
||||
import qualified Path.Aliases as Path
|
||||
|
||||
import CompileOptions (CompileOptions)
|
||||
import qualified CompileOptions
|
||||
import Wasp (Wasp)
|
||||
import qualified Wasp
|
||||
import qualified Generator.FileDraft as FD
|
||||
import qualified Generator.Common as Common
|
||||
import qualified ExternalCode
|
||||
import qualified Generator.FileDraft as FD
|
||||
import qualified Generator.ExternalCode.Common as Common
|
||||
import Generator.ExternalCode.Js (generateJsFile)
|
||||
|
||||
|
||||
externalCodeDirPathInSrc :: Path.RelDir
|
||||
externalCodeDirPathInSrc = [reldir|ext-src|]
|
||||
|
||||
generateExternalCodeDir :: CompileOptions -> Wasp -> [FD.FileDraft]
|
||||
generateExternalCodeDir compileOptions wasp =
|
||||
map (generateFile compileOptions) (Wasp.getExternalCodeFiles wasp)
|
||||
|
||||
-- | Returns path relative to the root of the generated project.
|
||||
getExtCodeFileDstPath :: ExternalCode.File -> Path.RelFile
|
||||
getExtCodeFileDstPath file = Common.srcDirPath </> externalCodeDirPathInSrc </>
|
||||
ExternalCode.getFilePathInExtCodeDir file
|
||||
|
||||
getExtCodeFileSrcPath :: CompileOptions -> ExternalCode.File -> Path.AbsFile
|
||||
getExtCodeFileSrcPath compileOptions file = CompileOptions.externalCodeDirPath compileOptions </>
|
||||
ExternalCode.getFilePathInExtCodeDir file
|
||||
|
||||
generateFile :: CompileOptions -> ExternalCode.File -> FD.FileDraft
|
||||
generateFile compileOptions file
|
||||
| extension `elem` ["js", "jsx"] = generateJsFile file
|
||||
| otherwise = FD.createCopyFileDraft (getExtCodeFileDstPath file) (getExtCodeFileSrcPath compileOptions file)
|
||||
| extension `elem` [".js", ".jsx"] = generateJsFile file
|
||||
| otherwise = FD.createCopyFileDraft (Common.getExtCodeFileDstPath file)
|
||||
(Common.getExtCodeFileSrcPath compileOptions file)
|
||||
where
|
||||
extension = takeExtension $ Path.toFilePath $ getExtCodeFileSrcPath compileOptions file
|
||||
|
||||
-- TODO: Now here we do preprocessing!
|
||||
generateJsFile :: ExternalCode.File -> FD.FileDraft
|
||||
generateJsFile file = FD.createTextFileDraft (getExtCodeFileDstPath file) (ExternalCode.getFileText file)
|
||||
extension = FP.takeExtension $ Path.toFilePath $ Common.getExtCodeFileSrcPath compileOptions file
|
||||
|
||||
|
||||
|
||||
|
31
src/Generator/ExternalCode/Common.hs
Normal file
31
src/Generator/ExternalCode/Common.hs
Normal file
@ -0,0 +1,31 @@
|
||||
module Generator.ExternalCode.Common
|
||||
( externalCodeDirPathInSrc
|
||||
, getExtCodeFileDstPath
|
||||
, getExtCodeFileSrcPath
|
||||
) where
|
||||
|
||||
import Path ((</>), reldir)
|
||||
import qualified Path.Aliases as Path
|
||||
|
||||
import CompileOptions (CompileOptions)
|
||||
import qualified CompileOptions
|
||||
import qualified ExternalCode
|
||||
import qualified Generator.Common as Common
|
||||
|
||||
|
||||
externalCodeDirPathInSrc :: Path.RelDir
|
||||
externalCodeDirPathInSrc = [reldir|ext-src|]
|
||||
|
||||
-- | Returns path where external code file will be generated,
|
||||
-- relative to the root of the generated project.
|
||||
getExtCodeFileDstPath :: ExternalCode.File -> Path.RelFile
|
||||
getExtCodeFileDstPath file = Common.srcDirPath </> externalCodeDirPathInSrc </>
|
||||
ExternalCode.getFilePathInExtCodeDir file
|
||||
|
||||
-- | Returns absolute path of the original external code file.
|
||||
getExtCodeFileSrcPath :: CompileOptions -> ExternalCode.File -> Path.AbsFile
|
||||
getExtCodeFileSrcPath compileOptions file = CompileOptions.externalCodeDirPath compileOptions </>
|
||||
ExternalCode.getFilePathInExtCodeDir file
|
||||
|
||||
|
||||
|
40
src/Generator/ExternalCode/Js.hs
Normal file
40
src/Generator/ExternalCode/Js.hs
Normal file
@ -0,0 +1,40 @@
|
||||
module Generator.ExternalCode.Js
|
||||
( generateJsFile
|
||||
-- FOR TESTING:
|
||||
, resolveJsFileWaspImports
|
||||
) where
|
||||
|
||||
import qualified Text.Regex as TR
|
||||
import Data.Text (Text, pack, unpack)
|
||||
import Path ((</>))
|
||||
import qualified Path
|
||||
import qualified Path.Aliases as Path
|
||||
import qualified Path.Extra as Path
|
||||
|
||||
import qualified Generator.FileDraft as FD
|
||||
import qualified ExternalCode
|
||||
import qualified Generator.ExternalCode.Common as Common
|
||||
|
||||
|
||||
generateJsFile :: ExternalCode.File -> FD.FileDraft
|
||||
generateJsFile file = FD.createTextFileDraft (Common.getExtCodeFileDstPath file) text'
|
||||
where
|
||||
text = ExternalCode.getFileText file
|
||||
text' = resolveJsFileWaspImports jsFilePathInSrcDir text
|
||||
jsFilePathInSrcDir = Common.externalCodeDirPathInSrc </>
|
||||
ExternalCode.getFilePathInExtCodeDir file
|
||||
|
||||
|
||||
-- | Takes a file path where the external code js file will be generated, relative to generated src dir.
|
||||
-- Also takes text of the file. Returns text where special @wasp imports have been replaced with
|
||||
-- imports that will work.
|
||||
-- TODO: I had hard time finding popular libraries for more advanced replacements, so for now
|
||||
-- I just used very simple regex replacement, which might not work in some complicated situations
|
||||
-- (it will also match on commens and strings and similar).
|
||||
-- For the future, we should probably use some kind of better regex or even some kind of parser.
|
||||
-- Possible candidates: replace-attoparsec.
|
||||
resolveJsFileWaspImports :: Path.RelFile -> Text -> Text
|
||||
resolveJsFileWaspImports jsFilePathInSrcDir jsFileText = pack $
|
||||
TR.subRegex (TR.mkRegex "(from\\s+['\"])@wasp/")
|
||||
(unpack jsFileText)
|
||||
("\\1" ++ Path.reversePath (Path.parent jsFilePathInSrcDir) ++ "/")
|
@ -14,12 +14,13 @@ import qualified System.FilePath as FP
|
||||
import Path ((</>), relfile, reldir)
|
||||
import qualified Path
|
||||
import qualified Path.Aliases as Path
|
||||
import qualified Path.Extra as Path
|
||||
|
||||
import qualified Util
|
||||
import Wasp
|
||||
import Generator.FileDraft
|
||||
import qualified Generator.Entity as EntityGenerator
|
||||
import Generator.ExternalCode (externalCodeDirPathInSrc)
|
||||
import Generator.ExternalCode.Common (externalCodeDirPathInSrc)
|
||||
import qualified Generator.Common as Common
|
||||
|
||||
|
||||
@ -81,16 +82,11 @@ generatePageComponent wasp page = createTemplateFileDraft dstPath srcPath (Just
|
||||
(fromJust $ Path.parseRelFile $ jsImportFrom jsImport))
|
||||
]
|
||||
|
||||
-- | NOTE: If you modify this value, make sure to also accordingly update relPathFromPageToSrc.
|
||||
-- For example, if pageDirPathInSrc = "foo/bar", then relPathFromPageToSrc should be "../../".
|
||||
pageDirPathInSrc :: Path.RelDir
|
||||
pageDirPathInSrc = [reldir|.|]
|
||||
-- | Relative path from page to the /src directory.
|
||||
-- It is the opposite of pageDirPathInSrc and should be updated together with it.
|
||||
-- TODO: We could deduce this directly from the pageDirPathInSrc instead of hardcoding it.
|
||||
-- NOTE: We are using FilePath instead of Path here because that allows us to assign values like "../".
|
||||
|
||||
relPathFromPageToSrc :: FilePath
|
||||
relPathFromPageToSrc = "."
|
||||
relPathFromPageToSrc = Path.reversePath pageDirPathInSrc
|
||||
|
||||
-- | Takes path relative to the src path of generated project and turns it into relative path that can be
|
||||
-- used as "from" part of the import in the Page source file.
|
||||
|
@ -1,7 +1,9 @@
|
||||
module Path.Extra
|
||||
( (./)
|
||||
, reversePath
|
||||
) where
|
||||
|
||||
import Control.Exception (assert)
|
||||
import System.FilePath as FP
|
||||
import Path
|
||||
|
||||
@ -11,3 +13,17 @@ import Path
|
||||
-- is to have it as a FilePath.
|
||||
(./) :: Path Rel a -> FP.FilePath
|
||||
(./) relPath = "." FP.</> (toFilePath relPath)
|
||||
|
||||
-- | For given path P, returns path P', such that (terminal pseudocode incoming)
|
||||
-- `pwd == (cd P && cd P' && pwd)`, or to put it differently, such that
|
||||
-- `cd P && cd P'` is noop (does nothing).
|
||||
-- It will always be either "." (only if input is ".") or a series of ".."
|
||||
-- (e.g. reversePath [reldir|foo/bar|] == "../..").
|
||||
reversePath :: Path Rel Dir -> FilePath
|
||||
reversePath path
|
||||
| length parts == 0 = "."
|
||||
| otherwise = assert (not (".." `elem` parts)) $
|
||||
FP.joinPath $ map (const "..") parts
|
||||
where
|
||||
parts :: [String]
|
||||
parts = filter (not . (== ".")) $ FP.splitDirectories $ toFilePath path
|
||||
|
19
test/Generator/ExternalCode/JsTest.hs
Normal file
19
test/Generator/ExternalCode/JsTest.hs
Normal file
@ -0,0 +1,19 @@
|
||||
module Generator.ExternalCode.JsTest where
|
||||
|
||||
import Test.Tasty.Hspec
|
||||
|
||||
import Path (relfile)
|
||||
|
||||
import Generator.ExternalCode.Js
|
||||
|
||||
|
||||
spec_resolveJsFileWaspImports :: Spec
|
||||
spec_resolveJsFileWaspImports = do
|
||||
([relfile|ext-src/extFile.js|], "import foo from 'bar'") ~> "import foo from 'bar'"
|
||||
([relfile|ext-src/extFile.js|], "import foo from '@wasp/bar'") ~> "import foo from '../bar'"
|
||||
([relfile|ext-src/a/extFile.js|], "import foo from \"@wasp/bar/foo\"") ~>
|
||||
"import foo from \"../../bar/foo\""
|
||||
where
|
||||
(path, text) ~> expectedText =
|
||||
it ((show path) ++ " " ++ (show text) ++ " -> " ++ (show expectedText)) $ do
|
||||
resolveJsFileWaspImports path text `shouldBe` expectedText
|
17
test/Path/ExtraTest.hs
Normal file
17
test/Path/ExtraTest.hs
Normal file
@ -0,0 +1,17 @@
|
||||
module Path.ExtraTest where
|
||||
|
||||
import Test.Tasty.Hspec
|
||||
|
||||
import Path (reldir)
|
||||
import qualified Path.Extra as PE
|
||||
|
||||
|
||||
spec_reversePath :: Spec
|
||||
spec_reversePath = do
|
||||
[reldir|.|] ~> "."
|
||||
[reldir|foo|] ~> ".."
|
||||
[reldir|foo/bar|] ~> "../.."
|
||||
[reldir|./foo/bar/./test|] ~> "../../.."
|
||||
where
|
||||
path ~> expectedReversedPath = it ((show path) ++ " -> " ++ expectedReversedPath) $ do
|
||||
PE.reversePath path `shouldBe` expectedReversedPath
|
Loading…
Reference in New Issue
Block a user