Просмотр исходного кода

refactor: include known properties by default in strict mode

e22m4u 2 недель назад
Родитель
Сommit
8fa96274b3
5 измененных файлов с 74 добавлено и 47 удалено
  1. 37 33
      README.md
  2. 1 0
      dist/cjs/index.cjs
  3. 1 1
      src/data-projector.spec.js
  4. 4 0
      src/project-data.js
  5. 31 13
      src/project-data.spec.js

+ 37 - 33
README.md

@@ -43,6 +43,10 @@ const {projectData} = require('@e22m4u/js-data-projector');
 {
   foo: true, // поле доступно
   bar: false // поле скрыто
+  // объект настроек
+  baz: {},              // поле доступно
+  qux: {select: true},  // поле доступно
+  buz: {select: false}, // поле скрыто
 }
 ```
 
@@ -50,12 +54,12 @@ const {projectData} = require('@e22m4u/js-data-projector');
 
 ```js
 {
-  name: true, // поле name доступно
-  address: {  // настройки поля address
-    select: true, // поле address доступно
+  name: true, // поле "name" доступно
+  address: {  // настройки поля "address"
+    select: true, // поле "address" доступно
     schema: {     // вложенная схема
-      city: true,     // поле city доступно
-      zip: false      // поле zip скрыто
+      city: true,     // поле "address.city" доступно
+      zip: false      // поле "address.zip" скрыто
     }
   }
 }
@@ -65,11 +69,11 @@ const {projectData} = require('@e22m4u/js-data-projector');
 
 ```js
 {
-  password: { // настройки поля password
-    select: false,  // поле password недоступно по умолчанию
-    scopes: {       // настройки для областей проекции
-      input: true,     // поле доступно для области 'input'
-      output: false    // но скрыто для области 'output'
+  password: { // настройки поля "password"
+    select: false, // поле "password" недоступно по умолчанию
+    scopes: {      // настройки для областей проекции
+      input: true,    // поле доступно для области "input"
+      output: false   // но скрыто для области "output"
     }
   }
 }
@@ -79,9 +83,9 @@ const {projectData} = require('@e22m4u/js-data-projector');
 
 ```js
 {
-  name: true, // поле name доступно
-  address: {  // настройки поля address
-    select: true,     // поле address доступно
+  name: true, // поле "name" доступно
+  address: {  // настройки поля "address"
+    select: true,     // поле "address" доступно
     schema: 'address' // имя вложенной схемы
   }
 }
@@ -104,9 +108,9 @@ const schema = {
 };
 
 const data = {
-  name: 'Fedor',       // будет доступно, явное правило
-  password: 'pass123', // будет исключено, явное правило
-  extra: 10,           // будет доступно в режиме по умолчанию
+  name: 'Fedor',       // допускается, явное правило
+  password: 'pass123', // исключается, явное правило
+  extra: 10,           // допускается в режиме по умолчанию
 };
 
 const result = projectData(data, schema);
@@ -149,7 +153,7 @@ const schema = {
   id: false,
   name: true,
   city: {
-    select: true, // правило видимости поля city
+    select: true, // правило видимости поля "city"
     schema: {     // вложенная схема
       id: false,
       name: true,
@@ -158,10 +162,10 @@ const schema = {
 };
 
 const data = {
-  id: 10, // будет скрыто, явное правило
+  id: 10, // исключается, явное правило
   name: 'Fedor',
   city: {
-    id: 20, // будет скрыто, явное правило
+    id: 20, // исключается, явное правило
     name: 'Moscow',
   },
 };
@@ -189,9 +193,9 @@ const schema = {
 };
 
 const data = {
-  name: 'Fedor',       // будет доступно, явное правило
-  password: 'pass123', // будет исключено, явное правило
-  extra: 10,           // будет исключено в строгом режиме
+  name: 'Fedor',       // допускается, явное правило
+  password: 'pass123', // исключается, явное правило
+  extra: 10,           // исключается в строгом режиме
 };
 
 const result = projectData(data, schema, {
@@ -214,19 +218,19 @@ const schema = {
   name: true,
   password: {
     scopes: {
-      input: true,   // правило для области 'input'
-      output: false, // правило для области 'output'
+      input: true,   // правило для области "input"
+      output: false, // правило для области "output"
     },
   },
 };
 
 const data = {
-  name: 'Fedor',       // будет доступно, явное правило
-  password: 'pass123', // будет доступно в зависимости от области
+  name: 'Fedor',       // допускается, явное правило
+  password: 'pass123', // исключается для области "output"
 };
 
 const inputData = projectData(data, schema, {
-  scope: 'input', // <= область видимости
+  scope: "input", // <= область видимости
 });
 console.log(inputData);
 // {
@@ -235,7 +239,7 @@ console.log(inputData);
 // }
 
 const outputData = projectData(data, schema, {
-  scope: 'output', // <= область видимости
+  scope: "output", // <= область видимости
 });
 console.log(outputData);
 // {
@@ -256,8 +260,8 @@ projector.defineSchema({
     username: true,
     password: {
       scopes: {
-        input: true,   // поле password доступно для "input" области
-        output: false, // поле password скрыто для "output" области
+        input: true,   // поле "password" доступно для области "input"
+        output: false, // поле "password" скрыто для области "output"
       },
     },
   },
@@ -268,7 +272,7 @@ const data = {
   password: 'secret123',
 }
 
-// аналог projector.project(data, 'user', {scope: 'input'})
+// аналог projector.project(data, 'user', {scope: "input"})
 const input = projector.projectInput(data, 'user');
 console.log(input);
 // {
@@ -276,7 +280,7 @@ console.log(input);
 //   password: 'secret123'
 // }
 
-// аналог projector.project(data, 'user', {scope: 'output'})
+// аналог projector.project(data, 'user', {scope: "output"})
 const output = projector.projectOutput(data, 'user');
 console.log(output);
 // {
@@ -466,7 +470,7 @@ projector.defineSchema({
   schema: {
     name: true,
     address: {
-      select: true,      // видимость поля address
+      select: true,      // видимость поля "address"
       schema: 'address', // <= имя вложенной схемы
     },
   },

+ 1 - 0
dist/cjs/index.cjs

@@ -229,6 +229,7 @@ function _shouldSelect(propOptions, strict, scope) {
     if (typeof propOptions.select === "boolean") {
       return propOptions.select;
     }
+    return true;
   }
   return !strict;
 }

+ 1 - 1
src/data-projector.spec.js

@@ -53,7 +53,7 @@ describe('DataProjector', function () {
       expect(res).to.be.eql({foo: 10, baz: 30});
     });
 
-    it('should exclude properties without rules in the strict mode', function () {
+    it('should exclude unknown properties in the strict mode', function () {
       const S = new DataProjector();
       S.defineSchema({name: 'mySchema', schema: {foo: true, bar: false}});
       const res = S.project({foo: 10, bar: 20, baz: 30}, 'mySchema', {

+ 4 - 0
src/project-data.js

@@ -222,6 +222,10 @@ function _shouldSelect(propOptions, strict, scope) {
     if (typeof propOptions.select === 'boolean') {
       return propOptions.select;
     }
+    // если настройки свойства являются объектом,
+    // но правила видимости не определены,
+    // то свойство считается видимым
+    return true;
   }
   // если правила видимости не определены
   // то результат будет зависеть от режима

+ 31 - 13
src/project-data.spec.js

@@ -364,7 +364,7 @@ describe('projectData', function () {
     expect(res).to.be.eql(expectedList);
   });
 
-  it('should exclude properties without rules when the strict mode is enabled', function () {
+  it('should exclude unknown properties when the strict mode is enabled', function () {
     const res = projectData(
       {foo: 10, bar: 20, baz: 30},
       {foo: true, bar: false},
@@ -373,6 +373,34 @@ describe('projectData', function () {
     expect(res).to.be.eql({foo: 10});
   });
 
+  it('should include a property defined with an empty object in the strict mode', function () {
+    const schema = {foo: {}, bar: {}};
+    const data = {foo: 10, baz: 30};
+    const res = projectData(data, schema, {strict: true});
+    expect(res).to.be.eql({foo: 10});
+  });
+
+  it('should include a property with a nested schema in the strict mode', function () {
+    const schema = {user: {schema: {id: true, name: false}}};
+    const data = {user: {id: 1, name: 'John Doe'}, timestamp: 12345};
+    const res = projectData(data, schema, {strict: true});
+    expect(res).to.be.eql({user: {id: 1}});
+  });
+
+  it('should exclude a property when the "select" option is false in the strict mode', function () {
+    const schema = {foo: {}, bar: {select: false}};
+    const data = {foo: 10, bar: 20};
+    const res = projectData(data, schema, {strict: true});
+    expect(res).to.be.eql({foo: 10});
+  });
+
+  it('should include a property when the "select" option is true in the strict mode', function () {
+    const schema = {foo: {}, bar: {select: true}};
+    const data = {foo: 10, bar: 20};
+    const res = projectData(data, schema, {strict: true});
+    expect(res).to.be.eql({foo: 10, bar: 20});
+  });
+
   it('should ignore prototype properties', function () {
     const data = Object.create({baz: 30});
     data.foo = 10;
@@ -440,7 +468,7 @@ describe('projectData', function () {
     expect(res).to.be.eql({foo: 10});
   });
 
-  it('should exclude properties without selection rule in the strict mode when the active scope is provided', function () {
+  it('should include a property in the strict mode if no rule for the active scope is specified', function () {
     const schema = {
       foo: {scopes: {input: true}},
       bar: {scopes: {input: false}},
@@ -448,7 +476,7 @@ describe('projectData', function () {
     };
     const data = {foo: 10, bar: 20, baz: 30, qux: 40};
     const res = projectData(data, schema, {strict: true, scope: 'input'});
-    expect(res).to.be.eql({foo: 10});
+    expect(res).to.be.eql({foo: 10, baz: 30});
   });
 
   it('should prioritize the scope options over the general options in the strict mode', function () {
@@ -470,14 +498,4 @@ describe('projectData', function () {
     const res = projectData(data, schema, {scope: 'input'});
     expect(res).to.be.eql({foo: 10, bar: {baz: 20, buz: 40}});
   });
-
-  it('should exclude nested properties without rules in the strict mode', function () {
-    const schema = {
-      foo: true,
-      bar: {select: true, schema: {baz: true, qux: false}},
-    };
-    const data = {foo: 10, bar: {baz: 20, qux: 30, buz: 40}};
-    const res = projectData(data, schema, {strict: true, scope: 'input'});
-    expect(res).to.be.eql({foo: 10, bar: {baz: 20}});
-  });
 });