fix: evaluate __can__ before branch conditions
This commit is contained in:
@@ -5,6 +5,10 @@ All notable changes to this project will be documented in this file.
|
|||||||
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
||||||
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
||||||
|
|
||||||
|
## [1.1.1] - 2025-11-15
|
||||||
|
### Changed
|
||||||
|
- Evaluate `__can__` guards before business expressions when merging into `v-if` / `v-else-if` branches to keep short-circuit order predictable.
|
||||||
|
|
||||||
## [1.1.0] - 2025-11-15
|
## [1.1.0] - 2025-11-15
|
||||||
### Added
|
### Added
|
||||||
- Automatically mirror `v-can` guards across `v-else-if` / `v-else` branches and surface the inferred expression in documentation and fixtures.
|
- Automatically mirror `v-can` guards across `v-else-if` / `v-else` branches and surface the inferred expression in documentation and fixtures.
|
||||||
@@ -35,6 +39,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|||||||
- English README describing usage, playground, and contribution guide.
|
- English README describing usage, playground, and contribution guide.
|
||||||
- Roadmap and release prep guidance.
|
- Roadmap and release prep guidance.
|
||||||
|
|
||||||
|
[1.1.1]: https://github.com/eduvia-app/nuxt-can/releases/tag/v1.1.1
|
||||||
[1.1.0]: https://github.com/eduvia-app/nuxt-can/releases/tag/v1.1.0
|
[1.1.0]: https://github.com/eduvia-app/nuxt-can/releases/tag/v1.1.0
|
||||||
[1.0.1]: https://github.com/eduvia-app/nuxt-can/releases/tag/v1.0.1
|
[1.0.1]: https://github.com/eduvia-app/nuxt-can/releases/tag/v1.0.1
|
||||||
[1.0.0]: https://github.com/eduvia-app/nuxt-can/releases/tag/v1.0.0
|
[1.0.0]: https://github.com/eduvia-app/nuxt-can/releases/tag/v1.0.0
|
||||||
|
|||||||
@@ -73,7 +73,7 @@ Now you can write directives that stay type-safe:
|
|||||||
|
|
||||||
```vue
|
```vue
|
||||||
<button v-if="__can__('employee', 'view')">View profile</button>
|
<button v-if="__can__('employee', 'view')">View profile</button>
|
||||||
<button v-if="(isReady) && __can__('employee', 'edit')">Edit profile</button>
|
<button v-if="__can__('employee', 'edit') && (isReady)">Edit profile</button>
|
||||||
<p v-if="!(__can__('employee', 'edit'))">Access denied</p>
|
<p v-if="!(__can__('employee', 'edit'))">Access denied</p>
|
||||||
```
|
```
|
||||||
|
|
||||||
@@ -101,10 +101,10 @@ Once the first branch of a conditional chain carries `v-can`, the transformer au
|
|||||||
Transforms into:
|
Transforms into:
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<div v-if="(status === 'draft') && __can__('foo', 'bar')">
|
<div v-if="__can__('foo', 'bar') && (status === 'draft')">
|
||||||
Draft state
|
Draft state
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="(status === 'pending') && __can__('foo', 'bar')">
|
<div v-else-if="__can__('foo', 'bar') && (status === 'pending')">
|
||||||
Pending state
|
Pending state
|
||||||
</div>
|
</div>
|
||||||
<div v-else-if="__can__('foo', 'bar')">
|
<div v-else-if="__can__('foo', 'bar')">
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ Ce document sert de guide de travail pour construire le plugin Nuxt et son trans
|
|||||||
### 🚀 Phase 4 — Transformation des nœuds `v-can`
|
### 🚀 Phase 4 — Transformation des nœuds `v-can`
|
||||||
- Convertir l’expression en chemin `['segment1','segment2',…]`.
|
- Convertir l’expression en chemin `['segment1','segment2',…]`.
|
||||||
- Chercher un `v-if` existant :
|
- Chercher un `v-if` existant :
|
||||||
- `v-if="expr"` → `v-if="(expr) && __can__(path)"`.
|
- `v-if="expr"` → `v-if="__can__(path) && (expr)"`.
|
||||||
- Sans `v-if` → ajouter `v-if="__can__(path)"`.
|
- Sans `v-if` → ajouter `v-if="__can__(path)"`.
|
||||||
- Interdire `v-can` sur des éléments possédant déjà `v-else` / `v-else-if` (lever une erreur compilateur).
|
- Interdire `v-can` sur des éléments possédant déjà `v-else` / `v-else-if` (lever une erreur compilateur).
|
||||||
|
|
||||||
@@ -125,7 +125,7 @@ Avant :
|
|||||||
Après compilation :
|
Après compilation :
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<div v-if="(isReady) && __can__('contract', 'edit')">
|
<div v-if="__can__('contract', 'edit') && (isReady)">
|
||||||
Modifier le contrat
|
Modifier le contrat
|
||||||
</div>
|
</div>
|
||||||
```
|
```
|
||||||
@@ -141,7 +141,7 @@ Avant :
|
|||||||
Après compilation :
|
Après compilation :
|
||||||
|
|
||||||
```vue
|
```vue
|
||||||
<button v-if="(ctaVisible) && __can__('employee', 'view')">Voir</button>
|
<button v-if="__can__('employee', 'view') && (ctaVisible)">Voir</button>
|
||||||
<p v-if="!__can__('employee', 'view')">Acces refuse</p>
|
<p v-if="!__can__('employee', 'view')">Acces refuse</p>
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@eduvia-app/nuxt-can",
|
"name": "@eduvia-app/nuxt-can",
|
||||||
"version": "1.1.0",
|
"version": "1.1.1",
|
||||||
"description": "Nuxt directives (`v-can`, `v-cannot`) to layer permissions without touching business v-ifs.",
|
"description": "Nuxt directives (`v-can`, `v-cannot`) to layer permissions without touching business v-ifs.",
|
||||||
"author": "Eduvia <engineering@eduvia.app>",
|
"author": "Eduvia <engineering@eduvia.app>",
|
||||||
"homepage": "https://github.com/eduvia-app/nuxt-can#readme",
|
"homepage": "https://github.com/eduvia-app/nuxt-can#readme",
|
||||||
|
|||||||
@@ -317,7 +317,7 @@ function mergeGuardIntoConditional(params: {
|
|||||||
ctx.patches.push({
|
ctx.patches.push({
|
||||||
start: ctx.templateStart + conditionDirective.loc.start.offset,
|
start: ctx.templateStart + conditionDirective.loc.start.offset,
|
||||||
end: ctx.templateStart + conditionDirective.loc.end.offset,
|
end: ctx.templateStart + conditionDirective.loc.end.offset,
|
||||||
text: `v-if="(${conditionExpression}) && ${canInvocation}"`,
|
text: `v-if="${canInvocation} && (${conditionExpression})"`,
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
@@ -333,7 +333,7 @@ function mergeGuardIntoConditional(params: {
|
|||||||
ctx.patches.push({
|
ctx.patches.push({
|
||||||
start: ctx.templateStart + conditionDirective.loc.start.offset,
|
start: ctx.templateStart + conditionDirective.loc.start.offset,
|
||||||
end: ctx.templateStart + conditionDirective.loc.end.offset,
|
end: ctx.templateStart + conditionDirective.loc.end.offset,
|
||||||
text: `v-else-if="(${conditionExpression}) && ${canInvocation}"`,
|
text: `v-else-if="${canInvocation} && (${conditionExpression})"`,
|
||||||
})
|
})
|
||||||
|
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ describe('transformCan', () => {
|
|||||||
<div v-if="isReady" v-can="can.contract.create" />
|
<div v-if="isReady" v-can="can.contract.create" />
|
||||||
`)
|
`)
|
||||||
|
|
||||||
expect(code).toContain(`v-if="(isReady) && __can__('contract', 'create')"`)
|
expect(code).toContain(`v-if="__can__('contract', 'create') && (isReady)"`)
|
||||||
})
|
})
|
||||||
|
|
||||||
it('throws when v-cannot is used without a preceding v-can', () => {
|
it('throws when v-cannot is used without a preceding v-can', () => {
|
||||||
@@ -56,8 +56,8 @@ describe('transformCan', () => {
|
|||||||
<p v-cannot>Denied</p>
|
<p v-cannot>Denied</p>
|
||||||
`)
|
`)
|
||||||
|
|
||||||
expect(code).toContain(`v-if="(ready) && __can__('employee', 'view')"`)
|
expect(code).toContain(`v-if="__can__('employee', 'view') && (ready)"`)
|
||||||
expect(code).toContain(`v-else-if="(later) && __can__('employee', 'view')"`)
|
expect(code).toContain(`v-else-if="__can__('employee', 'view') && (later)"`)
|
||||||
expect(code).toContain(`v-else-if="__can__('employee', 'view')"`)
|
expect(code).toContain(`v-else-if="__can__('employee', 'view')"`)
|
||||||
expect(code).toContain(`v-if="!(__can__('employee', 'view'))"`)
|
expect(code).toContain(`v-if="!(__can__('employee', 'view'))"`)
|
||||||
})
|
})
|
||||||
|
|||||||
Reference in New Issue
Block a user