Skip to content
This repository was archived by the owner on Feb 27, 2024. It is now read-only.

Commit a5367f4

Browse files
authored
Merge pull request #20 from protonemedia/resolve-once
Cleanup + improved JS object passing
2 parents e8844c0 + b1eb9e2 commit a5367f4

File tree

7 files changed

+58
-122
lines changed

7 files changed

+58
-122
lines changed

app/app/View/Components/ToVueProp.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ public function __construct(
4040
#[VueProp] public array $defaultArray = ['foo'],
4141
#[VueProp] public array|bool|string $multipleTypes = ['foo'],
4242
#[VueProp(as: 'renamed')] public string $name = 'renamed-foo',
43-
#[VuePropRaw] public string $json = '{"foo":"bar"}',
43+
#[VuePropRaw] public string $jsObject = "{foo: 'bar'}",
4444
) {
4545
}
4646

app/resources/views/components/to-vue-prop.blade.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,5 +18,5 @@
1818
<p>Multiple Types: <span v-text="multipleTypes" /> (<span v-text="typeof multipleTypes" />)</p>
1919
<p>Data From Method: <span v-text="dataFromMethod" /> (<span v-text="typeof dataFromMethod" />)</p>
2020
<p>Renamed: <span v-text="renamed" /> (<span v-text="typeof renamed" />)</p>
21-
<p>JSON: <span v-text="json" /> (<span v-text="typeof json" />)</p>
21+
<p>JS Object: <span v-text="jsObject" /> (<span v-text="typeof jsObject" />)</p>
2222
</div>

app/tests/Browser/ToVuePropTest.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ public function it_can_pass_blade_props_as_vue_rops()
3131
->assertSee('Multiple Types: [ "foo" ]')
3232
->assertSee('Data From Method: [ "foo", "bar", "baz" ]')
3333
->assertSee('Renamed: renamed-foo')
34-
->assertSee('JSON: { "foo": "bar" } (object)');
34+
->assertSee('JS Object: { "foo": "bar" } (object)');
3535
});
3636
}
3737
}

app/tests/Unit/Console/__snapshots__/BuildComponentsTest__it_builds_the_components__12.vue

Lines changed: 19 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4,25 +4,25 @@ import { h } from 'vue'
44
const props = defineProps({
55
spladeBridge: Object,
66
spladeTemplateId: String,
7-
mixed: { default: 'foo' },
8-
string: { type: String, default: 'foo' },
9-
defaultString: { type: String, default: 'foo' },
10-
nullableString: { type: String, default: null },
11-
int: { type: Number, default: null },
12-
bool: { type: Boolean, default: null },
13-
array: { type: Array, default: null },
14-
object: { type: Object, default: null },
15-
nullableInt: { type: Number, default: null },
16-
nullableBool: { type: Boolean, default: null },
17-
nullableArray: { type: Array, default: null },
18-
nullableObject: { type: Object, default: null },
19-
defaultInt: { type: Number, default: 1 },
20-
defaultBool: { type: Boolean, default: true },
21-
defaultArray: { type: Array, default: JSON.parse('[\u0022foo\u0022]') },
22-
multipleTypes: { type: [Array, String, Boolean], default: JSON.parse('[\u0022foo\u0022]') },
23-
renamed: { type: String, default: 'renamed-foo' },
24-
json: { default: JSON.parse('{\u0022foo\u0022:\u0022bar\u0022}') },
25-
dataFromMethod: { type: Array, default: null },
7+
mixed: {},
8+
string: { type: String },
9+
defaultString: { type: String },
10+
nullableString: { type: String },
11+
int: { type: Number },
12+
bool: { type: Boolean },
13+
array: { type: Array },
14+
object: { type: Object },
15+
nullableInt: { type: Number },
16+
nullableBool: { type: Boolean },
17+
nullableArray: { type: Array },
18+
nullableObject: { type: Object },
19+
defaultInt: { type: Number },
20+
defaultBool: { type: Boolean },
21+
defaultArray: { type: Array },
22+
multipleTypes: { type: [Array, String, Boolean] },
23+
renamed: { type: String },
24+
jsObject: {},
25+
dataFromMethod: { type: Array },
2626
})
2727
const spladeRender = h({
2828
name: 'SpladeComponentToVuePropRender',

src/BladeViewExtractor.php

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,9 @@
66
use Illuminate\Support\Arr;
77
use Illuminate\Support\Collection;
88
use Illuminate\Support\Facades\Process;
9-
use Illuminate\Support\Js;
109
use Illuminate\Support\Str;
1110
use InvalidArgumentException;
1211
use ProtoneMedia\SpladeCore\Facades\SpladePlugin;
13-
use ProtoneMedia\SpladeCore\View\Factory;
1412

1513
class BladeViewExtractor
1614
{
@@ -321,19 +319,13 @@ protected function extractDefinePropsFromScript(): array
321319
{
322320
$bladePropsAsVueProps = Collection::make($this->getBladePropsThatArePassedAsVueProps())
323321
->map(function (object $specs) {
324-
$default = $specs->raw
325-
? Factory::convertJsonToJavaScriptExpression($specs->default)
326-
: Js::from($specs->default)->toHtml();
327-
328322
$type = null;
329323

330324
if (! $specs->raw) {
331325
$type = is_array($specs->type) ? '['.implode(',', $specs->type).']' : "{$specs->type}";
332326
}
333327

334-
return $type
335-
? "{type: {$type}, default: {$default}}"
336-
: "{default: {$default}}";
328+
return $type ? "{type: {$type}}" : '{}';
337329
});
338330

339331
$defaultProps = Collection::make(['spladeTemplateId' => 'String'])

src/ComponentSerializer.php

Lines changed: 34 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@
1313
use ProtoneMedia\SpladeCore\Attributes\VueProp;
1414
use ProtoneMedia\SpladeCore\Attributes\VuePropRaw;
1515
use ProtoneMedia\SpladeCore\Attributes\VueRef;
16+
use ProtoneMedia\SpladeCore\Facades\Transformer;
1617
use ReflectionAttribute;
1718
use ReflectionClass;
1819
use ReflectionMethod;
@@ -83,6 +84,34 @@ public function toArray(array $with = [], bool $resolveImmediately = false): arr
8384
);
8485
}
8586

87+
/**
88+
* Transforms a Blade Component prop.
89+
*/
90+
private function transformValue(mixed $value): mixed
91+
{
92+
$value = Transformer::handle($value);
93+
94+
if ($value instanceof Model) {
95+
return (object) $value->jsonSerialize();
96+
}
97+
98+
if ($value instanceof Collection) {
99+
return $value->map(function ($item) {
100+
if ($item instanceof Model) {
101+
return (object) $item->jsonSerialize();
102+
}
103+
104+
return $item;
105+
})->jsonSerialize();
106+
}
107+
108+
if ($value instanceof JsonSerializable) {
109+
return $value->jsonSerialize();
110+
}
111+
112+
return $value;
113+
}
114+
86115
/**
87116
* Gathers all data that will be two-way bound to the Vue component.
88117
*/
@@ -107,27 +136,9 @@ public function getDataFromProperties(): array
107136
continue;
108137
}
109138

110-
$value = $property->getValue($this->component);
111-
112-
if ($value instanceof Model) {
113-
$value = (object) $value->jsonSerialize();
114-
}
115-
116-
if ($value instanceof Collection) {
117-
$value = $value->map(function ($item) {
118-
if ($item instanceof Model) {
119-
return (object) $item->jsonSerialize();
120-
}
121-
122-
return $item;
123-
})->jsonSerialize();
124-
}
125-
126-
if ($value instanceof JsonSerializable) {
127-
$value = $value->jsonSerialize();
128-
}
129-
130-
$values[$name] = $this->getSerializedPropertyValue($value);
139+
$values[$name] = $this->getSerializedPropertyValue(
140+
$property->getValue($this->component)
141+
);
131142
}
132143

133144
return $values;
@@ -192,7 +203,6 @@ public static function getPropsFromComponentClass(string $componentClass): array
192203

193204
// From Properties...
194205
$properties = (new ReflectionClass($componentClass))->getProperties();
195-
$constructorParameters = (new ReflectionClass($componentClass))->getConstructor()?->getParameters();
196206

197207
foreach ($properties as $property) {
198208
if ($property->isStatic() || ! $property->isPublic()) {
@@ -213,16 +223,7 @@ public static function getPropsFromComponentClass(string $componentClass): array
213223

214224
$as = $vuePropAttribute->getArguments()['as'] ?? $name;
215225

216-
$defaultValue = $property->getDefaultValue();
217-
218-
$constructorParameter = collect($constructorParameters)->first(fn ($parameter) => $parameter->getName() === $name);
219-
220-
if ($constructorParameter?->isDefaultValueAvailable()) {
221-
$defaultValue = $constructorParameter->getDefaultValue();
222-
}
223-
224226
$values[$as] = (object) [
225-
'default' => $defaultValue,
226227
'raw' => $vuePropAttribute->getName() === VuePropRaw::class,
227228
'type' => static::mapTypeToVueType($property->getType()),
228229
'value' => null,
@@ -253,7 +254,6 @@ public static function getPropsFromComponentClass(string $componentClass): array
253254
$as = $vuePropAttribute->getArguments()['as'] ?? $name;
254255

255256
$values[$as] = (object) [
256-
'default' => null,
257257
'raw' => $vuePropAttribute->getName() === VuePropRaw::class,
258258
'type' => static::mapTypeToVueType($method->getReturnType()),
259259
'value' => null,
@@ -264,15 +264,14 @@ public static function getPropsFromComponentClass(string $componentClass): array
264264
}
265265

266266
/**
267-
* Returns all public props from the component class.
267+
* Returns all public props from the component class (one-way bound).
268268
*/
269269
public function getPropsFromComponent(): array
270270
{
271271
$values = [];
272272

273273
// From Properties...
274274
$properties = (new ReflectionClass($this->component))->getProperties();
275-
$constructorParameters = (new ReflectionClass($this->component))->getConstructor()?->getParameters();
276275

277276
foreach ($properties as $property) {
278277
if ($property->isStatic() || ! $property->isPublic()) {
@@ -297,40 +296,10 @@ public function getPropsFromComponent(): array
297296
? $property->getValue($this->component)
298297
: null;
299298

300-
if ($value instanceof Model) {
301-
$value = (object) $value->jsonSerialize();
302-
}
303-
304-
if ($value instanceof Collection) {
305-
$value = $value->map(function ($item) {
306-
if ($item instanceof Model) {
307-
return (object) $item->jsonSerialize();
308-
}
309-
310-
return $item;
311-
})->jsonSerialize();
312-
}
313-
314-
if ($value instanceof JsonSerializable) {
315-
$value = $value->jsonSerialize();
316-
}
317-
318-
$defaultValue = $property->hasDefaultValue()
319-
? $property->getDefaultValue()
320-
: null;
321-
322-
$constructorParameter = collect($constructorParameters)
323-
->first(fn ($parameter) => $parameter->getName() === $name);
324-
325-
if ($constructorParameter?->isDefaultValueAvailable()) {
326-
$defaultValue = $constructorParameter->getDefaultValue();
327-
}
328-
329299
$values[$as] = (object) [
330-
'default' => $defaultValue,
331300
'raw' => $vuePropAttribute->getName() === VuePropRaw::class,
332301
'type' => static::mapTypeToVueType($property->getType()),
333-
'value' => $this->getSerializedPropertyValue($value),
302+
'value' => $this->getSerializedPropertyValue($this->transformValue($value)),
334303
];
335304
}
336305

@@ -358,7 +327,6 @@ public function getPropsFromComponent(): array
358327
$as = $vuePropAttribute->getArguments()['as'] ?? $name;
359328

360329
$values[$as] = (object) [
361-
'default' => null,
362330
'raw' => $vuePropAttribute->getName() === VuePropRaw::class,
363331
'type' => static::mapTypeToVueType($method->getReturnType()),
364332
'value' => Container::getInstance()->call([$this->component, $name]),

src/View/Factory.php

Lines changed: 1 addition & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,6 @@
1313

1414
class Factory extends BaseFactory
1515
{
16-
const REQUIRED_JSON_FLAGS = JSON_HEX_TAG | JSON_HEX_APOS | JSON_HEX_AMP | JSON_HEX_QUOT | JSON_THROW_ON_ERROR;
17-
1816
/**
1917
* Whether to track Splade components.
2018
*/
@@ -97,28 +95,6 @@ public function pushSpladeTemplate($id, $value): void
9795
);
9896
}
9997

100-
/**
101-
* Convert the given JSON to a JavaScript expression.
102-
*
103-
* @param string $json
104-
* @param int $flags
105-
* @return string
106-
*
107-
* @throws \JsonException
108-
*/
109-
public static function convertJsonToJavaScriptExpression($json, $flags = 0)
110-
{
111-
if ($json === '[]' || $json === '{}') {
112-
return $json;
113-
}
114-
115-
if (Str::startsWith($json, ['"', '{', '['])) {
116-
return "JSON.parse('".substr(json_encode($json, $flags | static::REQUIRED_JSON_FLAGS), 1, -1)."')";
117-
}
118-
119-
return $json;
120-
}
121-
12298
/**
12399
* Temporarily store the passed attributes, render the component and
124100
* push it to the Splade templates stack. Then return a generic Vue
@@ -178,7 +154,7 @@ public function renderComponent()
178154
}
179155

180156
$attributes[$key] = $specs->raw
181-
? static::convertJsonToJavaScriptExpression($specs->value)
157+
? $specs->value
182158
: Js::from($specs->value)->toHtml();
183159
});
184160

0 commit comments

Comments
 (0)