create-oc 0.0.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +63 -0
- package/package.json +16 -0
- package/templates/elm/elm.json +26 -0
- package/templates/elm/package.json +31 -0
- package/templates/elm/src/Main.elm +180 -0
- package/templates/elm/src/server.ts +22 -0
- package/templates/elm/tsconfig.json +18 -0
- package/templates/es6/css/styles.css +3 -0
- package/templates/es6/img/logo.png +0 -0
- package/templates/es6/oc-app.d.ts +1 -0
- package/templates/es6/package.json +31 -0
- package/templates/es6/server.ts +11 -0
- package/templates/es6/tsconfig.json +17 -0
- package/templates/es6/view.ts +10 -0
- package/templates/preact/.eslintrc.json +3 -0
- package/templates/preact/package.json +42 -0
- package/templates/preact/public/logo.png +0 -0
- package/templates/preact/src/App.test.tsx +28 -0
- package/templates/preact/src/App.tsx +52 -0
- package/templates/preact/src/oc-app.d.ts +1 -0
- package/templates/preact/src/server.ts +35 -0
- package/templates/preact/src/setupTests.js +1 -0
- package/templates/preact/src/styles.css +30 -0
- package/templates/preact/src/types.ts +15 -0
- package/templates/preact/tsconfig.json +27 -0
- package/templates/preact/vite.config.ts +11 -0
- package/templates/react/.eslintrc.json +3 -0
- package/templates/react/package.json +44 -0
- package/templates/react/public/logo.png +0 -0
- package/templates/react/src/App.test.tsx +39 -0
- package/templates/react/src/App.tsx +52 -0
- package/templates/react/src/oc-app.d.ts +1 -0
- package/templates/react/src/server.ts +37 -0
- package/templates/react/src/setupTests.js +1 -0
- package/templates/react/src/styles.css +30 -0
- package/templates/react/src/types.ts +15 -0
- package/templates/react/tsconfig.json +26 -0
- package/templates/react/vite.config.ts +11 -0
- package/templates/solid/package.json +42 -0
- package/templates/solid/public/logo.png +0 -0
- package/templates/solid/src/App.test.tsx +37 -0
- package/templates/solid/src/App.tsx +50 -0
- package/templates/solid/src/oc-app.d.ts +1 -0
- package/templates/solid/src/server.ts +36 -0
- package/templates/solid/src/setupTests.js +1 -0
- package/templates/solid/src/styles.css +30 -0
- package/templates/solid/src/types.ts +15 -0
- package/templates/solid/tsconfig.json +27 -0
- package/templates/solid/vite.config.ts +20 -0
package/index.js
ADDED
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import prompts from 'prompts';
|
|
2
|
+
import fs from 'fs';
|
|
3
|
+
|
|
4
|
+
const { componentName, template } = await prompts([
|
|
5
|
+
{
|
|
6
|
+
type: 'text',
|
|
7
|
+
name: 'componentName',
|
|
8
|
+
message: 'Component name',
|
|
9
|
+
initial: 'oc-component',
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
type: 'select',
|
|
13
|
+
name: 'template',
|
|
14
|
+
message: 'Select a template',
|
|
15
|
+
choices: [
|
|
16
|
+
{ title: 'Vanilla', value: 'es6' },
|
|
17
|
+
{ title: 'React', value: 'react' },
|
|
18
|
+
{ title: 'Solid', value: 'solid' },
|
|
19
|
+
{ title: 'Preact', value: 'preact' },
|
|
20
|
+
{ title: 'Elm', value: 'elm' },
|
|
21
|
+
],
|
|
22
|
+
},
|
|
23
|
+
]);
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
fs.mkdirSync(`./${componentName}`);
|
|
27
|
+
} catch (err) {
|
|
28
|
+
if (err.code === 'EEXIST') {
|
|
29
|
+
console.log('Folder already exists');
|
|
30
|
+
process.exit(1);
|
|
31
|
+
}
|
|
32
|
+
throw err;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
console.log();
|
|
36
|
+
console.log('Creating the template');
|
|
37
|
+
fs.cpSync(`./templates/${template}`, `./${componentName}`, {
|
|
38
|
+
recursive: true,
|
|
39
|
+
});
|
|
40
|
+
fs.writeFileSync(
|
|
41
|
+
`./${componentName}/.gitignore`,
|
|
42
|
+
['node_modules', '_package'].join('\n'),
|
|
43
|
+
'utf-8'
|
|
44
|
+
);
|
|
45
|
+
replaceJson(`./${componentName}/package.json`, (pkg) => ({
|
|
46
|
+
...pkg,
|
|
47
|
+
scripts: {
|
|
48
|
+
...(pkg.scripts || {}),
|
|
49
|
+
start: `oc dev .. --components ${componentName}`,
|
|
50
|
+
},
|
|
51
|
+
}));
|
|
52
|
+
|
|
53
|
+
console.log('Finished. To start your oc for the first time:');
|
|
54
|
+
console.log();
|
|
55
|
+
console.log(` cd ${componentName}`);
|
|
56
|
+
console.log(' npm install');
|
|
57
|
+
console.log(' npm start');
|
|
58
|
+
|
|
59
|
+
function replaceJson(file, transformer) {
|
|
60
|
+
const json = JSON.parse(fs.readFileSync(file, 'utf-8'));
|
|
61
|
+
const transformed = transformer(json);
|
|
62
|
+
fs.writeFileSync(file, JSON.stringify(transformed, null, 2), 'utf-8');
|
|
63
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "create-oc",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "",
|
|
6
|
+
"main": "index.js",
|
|
7
|
+
"scripts": {
|
|
8
|
+
"test": "echo \"Error: no test specified\" && exit 1"
|
|
9
|
+
},
|
|
10
|
+
"keywords": [],
|
|
11
|
+
"author": "",
|
|
12
|
+
"license": "ISC",
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"prompts": "^2.4.2"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"type": "application",
|
|
3
|
+
"source-directories": [
|
|
4
|
+
"src"
|
|
5
|
+
],
|
|
6
|
+
"elm-version": "0.19.1",
|
|
7
|
+
"dependencies": {
|
|
8
|
+
"direct": {
|
|
9
|
+
"elm/browser": "1.0.2",
|
|
10
|
+
"elm/core": "1.0.5",
|
|
11
|
+
"elm/html": "1.0.0",
|
|
12
|
+
"elm/json": "1.1.3",
|
|
13
|
+
"rtfeldman/elm-css": "16.1.1"
|
|
14
|
+
},
|
|
15
|
+
"indirect": {
|
|
16
|
+
"elm/time": "1.0.0",
|
|
17
|
+
"elm/url": "1.0.0",
|
|
18
|
+
"elm/virtual-dom": "1.0.2",
|
|
19
|
+
"rtfeldman/elm-hex": "1.0.0"
|
|
20
|
+
}
|
|
21
|
+
},
|
|
22
|
+
"test-dependencies": {
|
|
23
|
+
"direct": {},
|
|
24
|
+
"indirect": {}
|
|
25
|
+
}
|
|
26
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base-component-elm",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"scripts": {},
|
|
6
|
+
"oc": {
|
|
7
|
+
"files": {
|
|
8
|
+
"data": "src/server.ts",
|
|
9
|
+
"template": {
|
|
10
|
+
"src": "src/Main.elm",
|
|
11
|
+
"type": "oc-template-elm"
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
"parameters": {
|
|
15
|
+
"userId": {
|
|
16
|
+
"default": 1,
|
|
17
|
+
"description": "The user id from the user database",
|
|
18
|
+
"example": 1,
|
|
19
|
+
"mandatory": true,
|
|
20
|
+
"type": "number"
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
},
|
|
24
|
+
"dependencies": {},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"oc-server": "*",
|
|
27
|
+
"oc-template-elm-compiler": "*",
|
|
28
|
+
"elm": "*",
|
|
29
|
+
"typescript": "*"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
port module Main exposing (..)
|
|
2
|
+
|
|
3
|
+
import Browser
|
|
4
|
+
import Css exposing (..)
|
|
5
|
+
import Html.Styled exposing (..)
|
|
6
|
+
import Html.Styled.Attributes exposing (..)
|
|
7
|
+
import Html.Styled.Events exposing (onClick)
|
|
8
|
+
import Json.Decode as D
|
|
9
|
+
import Json.Encode as E
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
-- MAIN
|
|
14
|
+
|
|
15
|
+
|
|
16
|
+
main : Program E.Value Model Msg
|
|
17
|
+
main =
|
|
18
|
+
Browser.element
|
|
19
|
+
{ init = init
|
|
20
|
+
, view = view >> toUnstyled
|
|
21
|
+
, update = update
|
|
22
|
+
, subscriptions = subscriptions
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
-- MODEL
|
|
28
|
+
|
|
29
|
+
|
|
30
|
+
type alias Model =
|
|
31
|
+
{ userId : Int, name : String, email : String, age : Maybe Int }
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
type alias DataRequest =
|
|
35
|
+
{ userId : Int }
|
|
36
|
+
|
|
37
|
+
|
|
38
|
+
encode : DataRequest -> E.Value
|
|
39
|
+
encode data =
|
|
40
|
+
E.object
|
|
41
|
+
[ ( "userId", E.int data.userId )
|
|
42
|
+
, ( "moreData", E.bool True )
|
|
43
|
+
]
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
init : E.Value -> ( Model, Cmd Msg )
|
|
47
|
+
init flags =
|
|
48
|
+
( case D.decodeValue decoder flags of
|
|
49
|
+
Ok model ->
|
|
50
|
+
model
|
|
51
|
+
|
|
52
|
+
Err _ ->
|
|
53
|
+
{ name = "", email = "", userId = 0, age = Nothing }
|
|
54
|
+
, Cmd.none
|
|
55
|
+
)
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
isJust : Maybe a -> Bool
|
|
59
|
+
isJust data =
|
|
60
|
+
case data of
|
|
61
|
+
Nothing ->
|
|
62
|
+
False
|
|
63
|
+
|
|
64
|
+
_ ->
|
|
65
|
+
True
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
-- UPDATE
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
type Msg
|
|
73
|
+
= GetData
|
|
74
|
+
| Recv E.Value
|
|
75
|
+
|
|
76
|
+
|
|
77
|
+
update : Msg -> Model -> ( Model, Cmd Msg )
|
|
78
|
+
update msg model =
|
|
79
|
+
case msg of
|
|
80
|
+
GetData ->
|
|
81
|
+
( model, DataRequest model.userId |> encode |> getData )
|
|
82
|
+
|
|
83
|
+
Recv data ->
|
|
84
|
+
( case D.decodeValue decoder data of
|
|
85
|
+
Ok newModel ->
|
|
86
|
+
newModel
|
|
87
|
+
|
|
88
|
+
Err _ ->
|
|
89
|
+
{ name = "", email = "", userId = 0, age = Nothing }
|
|
90
|
+
, Cmd.none
|
|
91
|
+
)
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
|
|
95
|
+
-- VIEW
|
|
96
|
+
|
|
97
|
+
|
|
98
|
+
inputStyle : Style
|
|
99
|
+
inputStyle =
|
|
100
|
+
Css.batch
|
|
101
|
+
[ border3 (px 5) solid (rgb 255 240 255)
|
|
102
|
+
, boxShadow5 inset zero zero (px 8) (rgba 0 0 0 0.1)
|
|
103
|
+
, padding (px 15)
|
|
104
|
+
, backgroundColor (rgba 255 255 255 0.5)
|
|
105
|
+
, margin (px 10)
|
|
106
|
+
]
|
|
107
|
+
|
|
108
|
+
|
|
109
|
+
htmlIf : Html msg -> Bool -> Html msg
|
|
110
|
+
htmlIf el cond =
|
|
111
|
+
if cond then
|
|
112
|
+
el
|
|
113
|
+
|
|
114
|
+
else
|
|
115
|
+
text ""
|
|
116
|
+
|
|
117
|
+
|
|
118
|
+
view : Model -> Html Msg
|
|
119
|
+
view model =
|
|
120
|
+
div
|
|
121
|
+
[ css
|
|
122
|
+
[ padding (px 20)
|
|
123
|
+
]
|
|
124
|
+
]
|
|
125
|
+
[ input
|
|
126
|
+
[ css [ inputStyle ]
|
|
127
|
+
, type_ "text"
|
|
128
|
+
, placeholder "Name"
|
|
129
|
+
, value model.name
|
|
130
|
+
]
|
|
131
|
+
[]
|
|
132
|
+
, input
|
|
133
|
+
[ css [ inputStyle ]
|
|
134
|
+
, type_ "text"
|
|
135
|
+
, placeholder "Email"
|
|
136
|
+
, value model.email
|
|
137
|
+
]
|
|
138
|
+
[]
|
|
139
|
+
, case model.age of
|
|
140
|
+
Nothing ->
|
|
141
|
+
text ""
|
|
142
|
+
|
|
143
|
+
Just age ->
|
|
144
|
+
input
|
|
145
|
+
[ css [ inputStyle ]
|
|
146
|
+
, type_ "number"
|
|
147
|
+
, placeholder "Age"
|
|
148
|
+
, String.fromInt age |> value
|
|
149
|
+
]
|
|
150
|
+
[]
|
|
151
|
+
, button [ onClick GetData ] [ text "Get more data" ]
|
|
152
|
+
]
|
|
153
|
+
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
-- SUBSCRIPTIONS
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
subscriptions : Model -> Sub Msg
|
|
160
|
+
subscriptions _ =
|
|
161
|
+
dataReceiver Recv
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
decoder : D.Decoder Model
|
|
165
|
+
decoder =
|
|
166
|
+
D.map4 Model
|
|
167
|
+
(D.field "userId" D.int)
|
|
168
|
+
(D.field "name" D.string)
|
|
169
|
+
(D.field "email" D.string)
|
|
170
|
+
(D.maybe (D.field "age" D.int))
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
-- PORTS
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
port getData : E.Value -> Cmd msg
|
|
178
|
+
|
|
179
|
+
|
|
180
|
+
port dataReceiver : (E.Value -> msg) -> Sub msg
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Server } from 'oc-server';
|
|
2
|
+
|
|
3
|
+
const database = [
|
|
4
|
+
{ name: 'John Doe', email: 'john@doe.com', age: 32 },
|
|
5
|
+
{ name: 'Jane Doe', email: 'jane@doe.com', age: 31 }
|
|
6
|
+
];
|
|
7
|
+
|
|
8
|
+
async function getUser(userId: number) {
|
|
9
|
+
return database[userId];
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export const server = new Server(async (params: { userId: number; moreData?: boolean }) => {
|
|
13
|
+
const { moreData, userId } = params;
|
|
14
|
+
const { email, name, age } = await getUser(userId);
|
|
15
|
+
|
|
16
|
+
return {
|
|
17
|
+
userId,
|
|
18
|
+
name,
|
|
19
|
+
email,
|
|
20
|
+
age: moreData && age
|
|
21
|
+
};
|
|
22
|
+
});
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"allowJs": true,
|
|
6
|
+
"skipLibCheck": true,
|
|
7
|
+
"esModuleInterop": true,
|
|
8
|
+
"allowSyntheticDefaultImports": true,
|
|
9
|
+
"strict": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"module": "esnext",
|
|
12
|
+
"moduleResolution": "node",
|
|
13
|
+
"resolveJsonModule": true,
|
|
14
|
+
"isolatedModules": true
|
|
15
|
+
},
|
|
16
|
+
"include": ["src"],
|
|
17
|
+
"exclude": ["src/_package"]
|
|
18
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="oc-vite/client" />
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base-component-es6",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"oc": {
|
|
6
|
+
"files": {
|
|
7
|
+
"data": "server.js",
|
|
8
|
+
"static": [
|
|
9
|
+
"img",
|
|
10
|
+
"css"
|
|
11
|
+
],
|
|
12
|
+
"template": {
|
|
13
|
+
"src": "view.js",
|
|
14
|
+
"type": "oc-template-es6"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"parameters": {
|
|
18
|
+
"name": {
|
|
19
|
+
"default": "Jane Doe",
|
|
20
|
+
"description": "Your name",
|
|
21
|
+
"example": "Jane Doe",
|
|
22
|
+
"mandatory": false,
|
|
23
|
+
"type": "string"
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"oc-server": "*",
|
|
29
|
+
"oc-template-es6-compiler": "*"
|
|
30
|
+
}
|
|
31
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"target": "es5",
|
|
4
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
5
|
+
"strict": true,
|
|
6
|
+
"allowJs": true,
|
|
7
|
+
"skipLibCheck": true,
|
|
8
|
+
"esModuleInterop": true,
|
|
9
|
+
"allowSyntheticDefaultImports": true,
|
|
10
|
+
"forceConsistentCasingInFileNames": true,
|
|
11
|
+
"noFallthroughCasesInSwitch": true,
|
|
12
|
+
"module": "esnext",
|
|
13
|
+
"moduleResolution": "node",
|
|
14
|
+
"resolveJsonModule": true,
|
|
15
|
+
"isolatedModules": true
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base-component-react",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"lint": "eslint --max-warnings 0 --ext .js,.jsx,.ts,.tsx src",
|
|
7
|
+
"build": "tsc --noEmit && oc package .",
|
|
8
|
+
"test": "vitest"
|
|
9
|
+
},
|
|
10
|
+
"oc": {
|
|
11
|
+
"files": {
|
|
12
|
+
"data": "src/server.ts",
|
|
13
|
+
"template": {
|
|
14
|
+
"src": "src/App.tsx",
|
|
15
|
+
"type": "oc-template-preact"
|
|
16
|
+
},
|
|
17
|
+
"static": [
|
|
18
|
+
"public"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"parameters": {
|
|
22
|
+
"userId": {
|
|
23
|
+
"default": 1,
|
|
24
|
+
"description": "The user id from the user database",
|
|
25
|
+
"example": 1,
|
|
26
|
+
"mandatory": true,
|
|
27
|
+
"type": "number"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@testing-library/react": "^14.0.0",
|
|
34
|
+
"@testing-library/user-event": "^14.4.3",
|
|
35
|
+
"jsdom": "^21.1.1",
|
|
36
|
+
"oc-server": "*",
|
|
37
|
+
"oc-template-preact-compiler": "0.2.0",
|
|
38
|
+
"preact": "^10.13.2",
|
|
39
|
+
"typescript": "5.0.2",
|
|
40
|
+
"vitest": "^0.29.7"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { describe, it, afterEach, beforeEach, expect, vi } from 'vitest';
|
|
2
|
+
import { render, screen } from '@testing-library/react';
|
|
3
|
+
import { DataProvider } from 'oc-template-preact-compiler/dist/utils/useData';
|
|
4
|
+
|
|
5
|
+
import App from './App';
|
|
6
|
+
|
|
7
|
+
const getData = vi.fn();
|
|
8
|
+
|
|
9
|
+
describe('App - Page', () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
window.oc = { events: { on: vi.fn(), fire: vi.fn() } } as any;
|
|
12
|
+
});
|
|
13
|
+
afterEach(() => {
|
|
14
|
+
vi.restoreAllMocks();
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
it('Gets more data when clicking the button', () => {
|
|
18
|
+
getData.mockImplementationOnce(() => Promise.resolve({}));
|
|
19
|
+
render(
|
|
20
|
+
<DataProvider value={{ firstName: 'firstName', lastName: 'lastName', userId: 0, getData }}>
|
|
21
|
+
<App firstName="firstName" lastName="lastName" userId={0} />
|
|
22
|
+
</DataProvider>
|
|
23
|
+
);
|
|
24
|
+
|
|
25
|
+
const extraInfoButton = screen.getByText(/Get extra information/i);
|
|
26
|
+
expect(extraInfoButton).toBeTruthy();
|
|
27
|
+
});
|
|
28
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useState } from 'preact/hooks';
|
|
2
|
+
import { useData } from 'oc-template-preact-compiler/dist/utils/useData';
|
|
3
|
+
import { serverClient } from 'oc-server';
|
|
4
|
+
import styles from './styles.css';
|
|
5
|
+
import type { AdditionalData, ClientProps } from './types';
|
|
6
|
+
|
|
7
|
+
interface AppProps extends ClientProps {
|
|
8
|
+
getMoreData?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const App = () => {
|
|
12
|
+
const { firstName, lastName, userId, getData, getSetting } = useData<AppProps>();
|
|
13
|
+
const staticPath = getSetting('staticPath');
|
|
14
|
+
const [additionalData, setAdditionalData] = useState<AdditionalData | null>(null);
|
|
15
|
+
const [error, setError] = useState('');
|
|
16
|
+
|
|
17
|
+
const fetchMoreData = async () => {
|
|
18
|
+
setError('');
|
|
19
|
+
try {
|
|
20
|
+
const data = await serverClient.getMoreData({ userId });
|
|
21
|
+
setAdditionalData(data);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
setError(String(err));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (error) {
|
|
28
|
+
return <div>Something wrong happened!</div>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className={styles.container}>
|
|
33
|
+
<img width="50" height="50" src={`${staticPath}/public/logo.png`} alt="Logo" />
|
|
34
|
+
<h1 style={{ margin: '0 0 20px 0' }}>
|
|
35
|
+
Hello, <span style={{ textDecoration: 'underline' }}>{firstName}</span> {lastName}
|
|
36
|
+
</h1>
|
|
37
|
+
{additionalData && (
|
|
38
|
+
<div className={styles.info}>
|
|
39
|
+
<div className={styles.block}>Age: {additionalData.age}</div>
|
|
40
|
+
<div className={styles.block}>
|
|
41
|
+
Hobbies: {additionalData.hobbies.map((x) => x.toLowerCase()).join(', ')}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
<button className={styles.button} onClick={fetchMoreData}>
|
|
46
|
+
Get extra information
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default App;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="oc-vite/client" />
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import { Server } from 'oc-server';
|
|
2
|
+
import { AdditionalData, ClientProps, OcParameters } from './types';
|
|
3
|
+
|
|
4
|
+
const database = [
|
|
5
|
+
{ name: 'John Doe', age: 34, hobbies: ['Swimming', 'Basketball'] },
|
|
6
|
+
{ name: 'Jane Doe', age: 35, hobbies: ['Running', 'Rugby'] }
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
async function getUser(userId: number) {
|
|
10
|
+
return database[userId];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const server = new Server(async (params: OcParameters): Promise<ClientProps> => {
|
|
14
|
+
const user = await getUser(params.userId);
|
|
15
|
+
const [firstName, lastName] = user.name.split(/\s+/);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
userId: params.userId,
|
|
19
|
+
firstName,
|
|
20
|
+
lastName
|
|
21
|
+
};
|
|
22
|
+
}).action('getMoreData', async (params: OcParameters): Promise<AdditionalData> => {
|
|
23
|
+
const user = await getUser(params.userId);
|
|
24
|
+
|
|
25
|
+
return {
|
|
26
|
+
age: user.age,
|
|
27
|
+
hobbies: user.hobbies
|
|
28
|
+
};
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
declare module 'oc-server' {
|
|
32
|
+
interface Register {
|
|
33
|
+
server: typeof server;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
background-color: #3b246c;
|
|
3
|
+
color: #fff;
|
|
4
|
+
font-family: sans-serif;
|
|
5
|
+
padding: 40px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.button {
|
|
9
|
+
background-color: #a97613;
|
|
10
|
+
border: none;
|
|
11
|
+
padding: 15px 32px;
|
|
12
|
+
text-align: center;
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
display: inline-block;
|
|
16
|
+
color: inherit;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.info {
|
|
21
|
+
margin-bottom: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.block {
|
|
25
|
+
margin: 6px 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.button:hover {
|
|
29
|
+
background-color: #c79535;
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface OcParameters {
|
|
2
|
+
userId: number;
|
|
3
|
+
getMoreData?: boolean;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface AdditionalData {
|
|
7
|
+
hobbies: string[];
|
|
8
|
+
age: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ClientProps extends Partial<AdditionalData> {
|
|
12
|
+
userId: number;
|
|
13
|
+
firstName: string;
|
|
14
|
+
lastName: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// These are suggested values and will be set when not present in the
|
|
4
|
+
// tsconfig.json
|
|
5
|
+
// 'parsedValue' matches the output value from ts.parseJsonConfigFileContent()
|
|
6
|
+
"target": "es5",
|
|
7
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"noFallthroughCasesInSwitch": true,
|
|
15
|
+
|
|
16
|
+
// These values are required and cannot be changed by the user
|
|
17
|
+
// Keep this in sync with the rollup config
|
|
18
|
+
"module": "esnext",
|
|
19
|
+
"moduleResolution": "node",
|
|
20
|
+
"resolveJsonModule": true,
|
|
21
|
+
"isolatedModules": true,
|
|
22
|
+
"jsx": "react-jsx",
|
|
23
|
+
"jsxImportSource": "preact"
|
|
24
|
+
},
|
|
25
|
+
"include": ["src"],
|
|
26
|
+
"exclude": ["src/_package"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
// https://vitejs.dev/config/
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
// Add your own plugins here for thinkgs like eslint or typecheckers
|
|
6
|
+
plugins: [],
|
|
7
|
+
// @ts-ignore Missing test property
|
|
8
|
+
test: {
|
|
9
|
+
environment: 'jsdom'
|
|
10
|
+
}
|
|
11
|
+
});
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base-component-react",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"lint": "eslint --max-warnings 0 --ext .js,.jsx,.ts,.tsx src",
|
|
7
|
+
"build": "tsc --noEmit && oc package .",
|
|
8
|
+
"test": "vitest"
|
|
9
|
+
},
|
|
10
|
+
"oc": {
|
|
11
|
+
"files": {
|
|
12
|
+
"data": "src/server.ts",
|
|
13
|
+
"template": {
|
|
14
|
+
"src": "src/App.tsx",
|
|
15
|
+
"type": "oc-template-react"
|
|
16
|
+
},
|
|
17
|
+
"static": [
|
|
18
|
+
"public"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"parameters": {
|
|
22
|
+
"userId": {
|
|
23
|
+
"default": 1,
|
|
24
|
+
"description": "The user id from the user database",
|
|
25
|
+
"example": 1,
|
|
26
|
+
"mandatory": true,
|
|
27
|
+
"type": "number"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"dependencies": {},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@testing-library/react": "^14.0.0",
|
|
34
|
+
"@testing-library/user-event": "^14.4.3",
|
|
35
|
+
"@types/react": "^18.0.28",
|
|
36
|
+
"jsdom": "^21.1.1",
|
|
37
|
+
"oc-server": "*",
|
|
38
|
+
"oc-template-react-compiler": "6.0.0",
|
|
39
|
+
"react": "18.2.0",
|
|
40
|
+
"react-dom": "18.2.0",
|
|
41
|
+
"typescript": "5.1.3",
|
|
42
|
+
"vitest": "^0.32.2"
|
|
43
|
+
}
|
|
44
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import { describe, it, afterEach, beforeEach, expect, vi } from 'vitest';
|
|
3
|
+
import { render, screen } from '@testing-library/react';
|
|
4
|
+
import { DataProvider } from 'oc-template-react-compiler/dist/utils/useData';
|
|
5
|
+
|
|
6
|
+
import App from './App';
|
|
7
|
+
|
|
8
|
+
const getData = vi.fn();
|
|
9
|
+
const getSetting = vi.fn();
|
|
10
|
+
|
|
11
|
+
describe('App - Page', () => {
|
|
12
|
+
beforeEach(() => {
|
|
13
|
+
window.oc = { events: { on: vi.fn(), fire: vi.fn() } } as any;
|
|
14
|
+
});
|
|
15
|
+
afterEach(() => {
|
|
16
|
+
vi.restoreAllMocks();
|
|
17
|
+
});
|
|
18
|
+
|
|
19
|
+
it('Gets more data when clicking the button', () => {
|
|
20
|
+
getData.mockImplementationOnce(() => Promise.resolve({}));
|
|
21
|
+
getSetting.mockImplementationOnce(() => ({}));
|
|
22
|
+
render(
|
|
23
|
+
<DataProvider
|
|
24
|
+
value={{
|
|
25
|
+
firstName: 'firstName',
|
|
26
|
+
lastName: 'lastName',
|
|
27
|
+
userId: 0,
|
|
28
|
+
getData,
|
|
29
|
+
getSetting
|
|
30
|
+
}}
|
|
31
|
+
>
|
|
32
|
+
<App firstName="firstName" lastName="lastName" userId={0} />
|
|
33
|
+
</DataProvider>
|
|
34
|
+
);
|
|
35
|
+
|
|
36
|
+
const extraInfoButton = screen.getByText(/Get extra information/i);
|
|
37
|
+
expect(extraInfoButton).toBeTruthy();
|
|
38
|
+
});
|
|
39
|
+
});
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
import { useData } from 'oc-template-react-compiler/dist/utils/useData';
|
|
3
|
+
import { serverClient } from 'oc-server';
|
|
4
|
+
import styles from './styles.css';
|
|
5
|
+
import logo from '../public/logo.png';
|
|
6
|
+
import type { AdditionalData, ClientProps } from './types';
|
|
7
|
+
|
|
8
|
+
interface AppProps extends ClientProps {
|
|
9
|
+
getMoreData?: boolean;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
const App: React.FC<ClientProps> = () => {
|
|
13
|
+
const { firstName, lastName, userId, getData } = useData<AppProps>();
|
|
14
|
+
const [additionalData, setAdditionalData] = useState<AdditionalData | null>(null);
|
|
15
|
+
const [error, setError] = useState('');
|
|
16
|
+
|
|
17
|
+
const fetchMoreData = async () => {
|
|
18
|
+
setError('');
|
|
19
|
+
try {
|
|
20
|
+
const data = await serverClient.getMoreData({ userId });
|
|
21
|
+
setAdditionalData(data);
|
|
22
|
+
} catch (err) {
|
|
23
|
+
setError(String(err));
|
|
24
|
+
}
|
|
25
|
+
};
|
|
26
|
+
|
|
27
|
+
if (error) {
|
|
28
|
+
return <div>Something wrong happened!</div>;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return (
|
|
32
|
+
<div className={styles.container}>
|
|
33
|
+
<img width="50" height="50" src={logo} alt="Logo" />
|
|
34
|
+
<h1 style={{ margin: '0 0 20px 0' }}>
|
|
35
|
+
Hello, <span style={{ textDecoration: 'underline' }}>{firstName}</span> {lastName}
|
|
36
|
+
</h1>
|
|
37
|
+
{additionalData && (
|
|
38
|
+
<div className={styles.info}>
|
|
39
|
+
<div className={styles.block}>Age: {additionalData.age}</div>
|
|
40
|
+
<div className={styles.block}>
|
|
41
|
+
Hobbies: {additionalData.hobbies.map((x) => x.toLowerCase()).join(', ')}
|
|
42
|
+
</div>
|
|
43
|
+
</div>
|
|
44
|
+
)}
|
|
45
|
+
<button className={styles.button} onClick={fetchMoreData}>
|
|
46
|
+
Get extra information
|
|
47
|
+
</button>
|
|
48
|
+
</div>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default App;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="oc-vite/client" />
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { Server } from 'oc-server';
|
|
2
|
+
import { AdditionalData, ClientProps, OcParameters } from './types';
|
|
3
|
+
|
|
4
|
+
const database = [
|
|
5
|
+
{ name: 'John Doe', age: 34, hobbies: ['Swimming', 'Basketball'] },
|
|
6
|
+
{ name: 'Jane Doe', age: 35, hobbies: ['Running', 'Rugby'] }
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
async function getUser(userId: number) {
|
|
10
|
+
return database[userId];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const server = new Server(async (params: OcParameters): Promise<ClientProps> => {
|
|
14
|
+
const { userId } = params;
|
|
15
|
+
const user = await getUser(userId);
|
|
16
|
+
const [firstName, lastName] = user.name.split(/\s+/);
|
|
17
|
+
|
|
18
|
+
return {
|
|
19
|
+
userId,
|
|
20
|
+
firstName,
|
|
21
|
+
lastName
|
|
22
|
+
};
|
|
23
|
+
}).action('getMoreData', async (params: OcParameters): Promise<AdditionalData> => {
|
|
24
|
+
const { userId } = params;
|
|
25
|
+
const user = await getUser(userId);
|
|
26
|
+
|
|
27
|
+
return {
|
|
28
|
+
age: user.age,
|
|
29
|
+
hobbies: user.hobbies
|
|
30
|
+
};
|
|
31
|
+
});
|
|
32
|
+
|
|
33
|
+
declare module 'oc-server' {
|
|
34
|
+
interface Register {
|
|
35
|
+
server: typeof server;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
background-color: #3b246c;
|
|
3
|
+
color: #fff;
|
|
4
|
+
font-family: sans-serif;
|
|
5
|
+
padding: 40px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.button {
|
|
9
|
+
background-color: #a97613;
|
|
10
|
+
border: none;
|
|
11
|
+
padding: 15px 32px;
|
|
12
|
+
text-align: center;
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
display: inline-block;
|
|
16
|
+
color: inherit;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.info {
|
|
21
|
+
margin-bottom: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.block {
|
|
25
|
+
margin: 6px 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.button:hover {
|
|
29
|
+
background-color: #c79535;
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface OcParameters {
|
|
2
|
+
userId: number;
|
|
3
|
+
getMoreData?: boolean;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface AdditionalData {
|
|
7
|
+
hobbies: string[];
|
|
8
|
+
age: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ClientProps extends Partial<AdditionalData> {
|
|
12
|
+
userId: number;
|
|
13
|
+
firstName: string;
|
|
14
|
+
lastName: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// These are suggested values and will be set when not present in the
|
|
4
|
+
// tsconfig.json
|
|
5
|
+
// 'parsedValue' matches the output value from ts.parseJsonConfigFileContent()
|
|
6
|
+
"target": "es5",
|
|
7
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"noFallthroughCasesInSwitch": true,
|
|
15
|
+
|
|
16
|
+
// These values are required and cannot be changed by the user
|
|
17
|
+
// Keep this in sync with the rollup config
|
|
18
|
+
"module": "ESNext",
|
|
19
|
+
"moduleResolution": "Node",
|
|
20
|
+
"resolveJsonModule": true,
|
|
21
|
+
"isolatedModules": true,
|
|
22
|
+
"jsx": "react-jsx"
|
|
23
|
+
},
|
|
24
|
+
"include": ["src"],
|
|
25
|
+
"exclude": ["src/_package"]
|
|
26
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
|
|
3
|
+
// https://vitejs.dev/config/
|
|
4
|
+
export default defineConfig({
|
|
5
|
+
// Add your own plugins here for thinkgs like eslint or typecheckers
|
|
6
|
+
plugins: [],
|
|
7
|
+
// @ts-ignore Missing test property
|
|
8
|
+
test: {
|
|
9
|
+
environment: 'jsdom'
|
|
10
|
+
}
|
|
11
|
+
});
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "base-component-solid",
|
|
3
|
+
"description": "",
|
|
4
|
+
"version": "1.0.0",
|
|
5
|
+
"scripts": {
|
|
6
|
+
"lint": "eslint --max-warnings 0 --ext .js,.jsx,.ts,.tsx src",
|
|
7
|
+
"build": "tsc --noEmit && oc package .",
|
|
8
|
+
"test": "vitest"
|
|
9
|
+
},
|
|
10
|
+
"oc": {
|
|
11
|
+
"files": {
|
|
12
|
+
"data": "src/server.ts",
|
|
13
|
+
"template": {
|
|
14
|
+
"src": "src/App.tsx",
|
|
15
|
+
"type": "oc-template-solid"
|
|
16
|
+
},
|
|
17
|
+
"static": [
|
|
18
|
+
"public"
|
|
19
|
+
]
|
|
20
|
+
},
|
|
21
|
+
"parameters": {
|
|
22
|
+
"userId": {
|
|
23
|
+
"default": 1,
|
|
24
|
+
"description": "The user id from the user database",
|
|
25
|
+
"example": 1,
|
|
26
|
+
"mandatory": true,
|
|
27
|
+
"type": "number"
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@solidjs/testing-library": "^0.7.0",
|
|
33
|
+
"@testing-library/jest-dom": "^5.16.5",
|
|
34
|
+
"@types/testing-library__jest-dom": "^5.14.5",
|
|
35
|
+
"jsdom": "^21.1.1",
|
|
36
|
+
"oc-server": "*",
|
|
37
|
+
"oc-template-solid-compiler": "0.4.0",
|
|
38
|
+
"solid-js": "^1.8.7",
|
|
39
|
+
"typescript": "5.0.2",
|
|
40
|
+
"vitest": "^0.29.7"
|
|
41
|
+
}
|
|
42
|
+
}
|
|
Binary file
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { describe, it, afterEach, beforeEach, expect, vi } from 'vitest';
|
|
2
|
+
import { render } from '@solidjs/testing-library';
|
|
3
|
+
import { DataProvider } from 'oc-template-solid-compiler/dist/utils/useData';
|
|
4
|
+
|
|
5
|
+
import App from './App';
|
|
6
|
+
|
|
7
|
+
const getData = vi.fn();
|
|
8
|
+
const getSetting = vi.fn();
|
|
9
|
+
|
|
10
|
+
describe('App - Page', () => {
|
|
11
|
+
beforeEach(() => {
|
|
12
|
+
window.oc = { events: { on: vi.fn(), fire: vi.fn() } } as any;
|
|
13
|
+
});
|
|
14
|
+
afterEach(() => {
|
|
15
|
+
vi.restoreAllMocks();
|
|
16
|
+
});
|
|
17
|
+
|
|
18
|
+
it('Gets more data when clicking the button', () => {
|
|
19
|
+
getData.mockImplementationOnce(() => Promise.resolve({}));
|
|
20
|
+
const { getByText } = render(() => (
|
|
21
|
+
<DataProvider
|
|
22
|
+
value={{
|
|
23
|
+
firstName: 'firstName',
|
|
24
|
+
lastName: 'lastName',
|
|
25
|
+
userId: 0,
|
|
26
|
+
getData,
|
|
27
|
+
getSetting
|
|
28
|
+
}}
|
|
29
|
+
>
|
|
30
|
+
<App />
|
|
31
|
+
</DataProvider>
|
|
32
|
+
));
|
|
33
|
+
|
|
34
|
+
const extraInfoButton = getByText(/Get extra information/i);
|
|
35
|
+
expect(extraInfoButton).toBeTruthy();
|
|
36
|
+
});
|
|
37
|
+
});
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { createSignal, Show, For } from 'solid-js';
|
|
2
|
+
import { useData } from 'oc-template-solid-compiler/dist/utils/useData';
|
|
3
|
+
import { serverClient } from 'oc-server';
|
|
4
|
+
import styles from './styles.css';
|
|
5
|
+
import type { AdditionalData, ClientProps } from './types';
|
|
6
|
+
|
|
7
|
+
interface AppProps extends ClientProps {
|
|
8
|
+
getMoreData?: boolean;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const App = () => {
|
|
12
|
+
const { firstName, lastName, userId, getSetting } = useData<AppProps>();
|
|
13
|
+
const staticPath = getSetting('staticPath');
|
|
14
|
+
const [additionalData, setAdditionalData] = createSignal<AdditionalData | null>(null);
|
|
15
|
+
const [error, setError] = createSignal('');
|
|
16
|
+
|
|
17
|
+
async function handleClick() {
|
|
18
|
+
const data = await serverClient.getMoreData({ userId });
|
|
19
|
+
|
|
20
|
+
try {
|
|
21
|
+
setAdditionalData(data);
|
|
22
|
+
} catch (error) {
|
|
23
|
+
setError(String(error));
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
return (
|
|
28
|
+
<Show when={!error()} fallback={<div>Something wrong happened!</div>}>
|
|
29
|
+
<div class={styles.container}>
|
|
30
|
+
<img width="50" height="50" src={`${staticPath}/public/logo.png`} alt="Logo" />
|
|
31
|
+
<h1 style={{ margin: '0 0 20px 0' }}>
|
|
32
|
+
Hello, <span style={{ 'text-decoration': 'underline' }}>{firstName}</span> {lastName}
|
|
33
|
+
</h1>
|
|
34
|
+
<Show when={!!additionalData()}>
|
|
35
|
+
<div class={styles.info}>
|
|
36
|
+
<div class={styles.block}>Age: {additionalData()!.age}</div>
|
|
37
|
+
<div class={styles.block}>
|
|
38
|
+
Hobbies: <For each={additionalData()!.hobbies}>{(hobby) => <div>{hobby}</div>}</For>
|
|
39
|
+
</div>
|
|
40
|
+
</div>
|
|
41
|
+
</Show>
|
|
42
|
+
<button class={styles.button} onClick={handleClick}>
|
|
43
|
+
Get extra information
|
|
44
|
+
</button>
|
|
45
|
+
</div>
|
|
46
|
+
</Show>
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default App;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
/// <reference types="oc-vite/client" />
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { Server } from 'oc-server';
|
|
2
|
+
import { ClientProps, OcParameters } from './types';
|
|
3
|
+
|
|
4
|
+
const database = [
|
|
5
|
+
{ name: 'John Doe', age: 34, hobbies: ['Swimming', 'Basketball'] },
|
|
6
|
+
{ name: 'Jane Doe', age: 35, hobbies: ['Running', 'Rugby'] }
|
|
7
|
+
];
|
|
8
|
+
|
|
9
|
+
async function getUser(userId: number) {
|
|
10
|
+
return database[userId];
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export const server = new Server(async (params: OcParameters): Promise<ClientProps> => {
|
|
14
|
+
const { userId } = params;
|
|
15
|
+
const user = await getUser(userId);
|
|
16
|
+
|
|
17
|
+
const [firstName, lastName] = user.name.split(/\s+/);
|
|
18
|
+
return {
|
|
19
|
+
userId,
|
|
20
|
+
firstName,
|
|
21
|
+
lastName
|
|
22
|
+
};
|
|
23
|
+
}).action('getMoreData', async (params: OcParameters) => {
|
|
24
|
+
const { userId } = params;
|
|
25
|
+
const user = await getUser(userId);
|
|
26
|
+
return {
|
|
27
|
+
age: user.age,
|
|
28
|
+
hobbies: user.hobbies
|
|
29
|
+
};
|
|
30
|
+
});
|
|
31
|
+
|
|
32
|
+
declare module 'oc-server' {
|
|
33
|
+
interface Register {
|
|
34
|
+
server: typeof server;
|
|
35
|
+
}
|
|
36
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import '@testing-library/jest-dom';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
.container {
|
|
2
|
+
background-color: #3b246c;
|
|
3
|
+
color: #fff;
|
|
4
|
+
font-family: sans-serif;
|
|
5
|
+
padding: 40px;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.button {
|
|
9
|
+
background-color: #a97613;
|
|
10
|
+
border: none;
|
|
11
|
+
padding: 15px 32px;
|
|
12
|
+
text-align: center;
|
|
13
|
+
font-size: 16px;
|
|
14
|
+
text-decoration: none;
|
|
15
|
+
display: inline-block;
|
|
16
|
+
color: inherit;
|
|
17
|
+
cursor: pointer;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
.info {
|
|
21
|
+
margin-bottom: 20px;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.block {
|
|
25
|
+
margin: 6px 0;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
.button:hover {
|
|
29
|
+
background-color: #c79535;
|
|
30
|
+
}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export interface OcParameters {
|
|
2
|
+
userId: number;
|
|
3
|
+
getMoreData?: boolean;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface AdditionalData {
|
|
7
|
+
hobbies: string[];
|
|
8
|
+
age: number;
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
export interface ClientProps extends Partial<AdditionalData> {
|
|
12
|
+
userId: number;
|
|
13
|
+
firstName: string;
|
|
14
|
+
lastName: string;
|
|
15
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
// These are suggested values and will be set when not present in the
|
|
4
|
+
// tsconfig.json
|
|
5
|
+
// 'parsedValue' matches the output value from ts.parseJsonConfigFileContent()
|
|
6
|
+
"target": "es5",
|
|
7
|
+
"lib": ["dom", "dom.iterable", "esnext"],
|
|
8
|
+
"strict": true,
|
|
9
|
+
"allowJs": true,
|
|
10
|
+
"skipLibCheck": true,
|
|
11
|
+
"esModuleInterop": true,
|
|
12
|
+
"allowSyntheticDefaultImports": true,
|
|
13
|
+
"forceConsistentCasingInFileNames": true,
|
|
14
|
+
"noFallthroughCasesInSwitch": true,
|
|
15
|
+
|
|
16
|
+
// These values are required and cannot be changed by the user
|
|
17
|
+
// Keep this in sync with the rollup config
|
|
18
|
+
"module": "esnext",
|
|
19
|
+
"moduleResolution": "node",
|
|
20
|
+
"resolveJsonModule": true,
|
|
21
|
+
"isolatedModules": true,
|
|
22
|
+
"jsx": "preserve",
|
|
23
|
+
"jsxImportSource": "solid-js"
|
|
24
|
+
},
|
|
25
|
+
"include": ["src"],
|
|
26
|
+
"exclude": ["src/_package"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { defineConfig } from 'vite';
|
|
2
|
+
import solidPlugin from 'vite-plugin-solid';
|
|
3
|
+
|
|
4
|
+
// https://vitejs.dev/config/
|
|
5
|
+
export default defineConfig({
|
|
6
|
+
plugins: [solidPlugin()],
|
|
7
|
+
// @ts-ignore Missing test property
|
|
8
|
+
test: {
|
|
9
|
+
environment: 'jsdom',
|
|
10
|
+
globals: true,
|
|
11
|
+
transformMode: { web: [/\.[jt]sx?$/] },
|
|
12
|
+
setupFiles: ['node_modules/@testing-library/jest-dom/extend-expect.js'],
|
|
13
|
+
// otherwise, solid would be loaded twice:
|
|
14
|
+
deps: { registerNodeLoader: true },
|
|
15
|
+
// if you have few tests, try commenting one
|
|
16
|
+
// or both out to improve performance:
|
|
17
|
+
threads: false,
|
|
18
|
+
isolate: false,
|
|
19
|
+
},
|
|
20
|
+
});
|