spyne 0.20.19 → 0.21.2

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.
@@ -1,5 +1,5 @@
1
1
  /*!
2
- * Spyne 0.20.19
2
+ * Spyne 0.21.2
3
3
  * https://spynejs.org
4
4
  *
5
5
  * @license
@@ -15,7 +15,7 @@
15
15
  */
16
16
 
17
17
  /*!
18
- * spynejs 0.20.19
18
+ * spynejs 0.21.2
19
19
  * https://spynejs.org
20
20
  * (c) 2017-present Frank Batista
21
21
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spyne",
3
- "version": "0.20.19",
3
+ "version": "0.21.2",
4
4
  "description": "Reactive Real-DOM Framework for Advanced Javascript applications",
5
5
  "sideEffects": true,
6
6
  "main": "./lib/spyne.esm.js",
@@ -6,7 +6,7 @@ import { sanitizeHTMLConfigure } from './utils/sanitize-html.js'
6
6
  import { sanitizeDataConfigure } from './utils/sanitize-data.js'
7
7
 
8
8
  const _channels = new ChannelsMap()
9
- const version = '0.20.19'
9
+ const version = '0.21.2'
10
10
 
11
11
  class SpyneApplication {
12
12
  /**
@@ -32,8 +32,6 @@ class SpyneApplication {
32
32
 
33
33
  constructor() {
34
34
  this.version = version
35
-
36
- // console.log('spyne app created')
37
35
  }
38
36
 
39
37
  get channels() {
@@ -43,7 +41,7 @@ class SpyneApplication {
43
41
  init(config = {}, testMode = false) {
44
42
  // this.channels = new ChannelsMap();
45
43
  /*!
46
- * Spyne 0.20.19
44
+ * Spyne 0.21.2
47
45
  * https://spynejs.org
48
46
  *
49
47
  * @license
@@ -59,9 +57,6 @@ class SpyneApplication {
59
57
  */
60
58
  /* eslint-disable */
61
59
 
62
-
63
-
64
-
65
60
  if(SpyneAppProperties.initialized === true){
66
61
  if (testMode){
67
62
  return 'The Spyne Application has already been initialized!';
@@ -15,15 +15,16 @@ const SAFE_FOR_RICH_TEXT = {
15
15
  'blockquote', 'pre', 'code', 'span', 'div', 'section', 'article', 'aside',
16
16
  'header', 'footer', 'h1', 'h2', 'h3', 'h4', 'h5', 'h6',
17
17
  'table', 'thead', 'tbody', 'tr', 'td', 'th', 'img', 'figure', 'figcaption',
18
- 'video', 'source'
18
+ 'video', 'source', 'iframe', 'input', 'button', 'label', 'link'
19
19
  ],
20
+ ADD_TAGS: ['iframe', 'input', 'button', 'link'],
20
21
  ALLOWED_ATTR: [
21
- 'href', 'src', 'alt', 'title', 'width', 'height', 'style', 'target', 'rel',
22
+ 'href', 'src', 'alt', 'class', 'title', 'width', 'height', 'style', 'target', 'rel',
22
23
  'controls', 'poster', 'type', 'rows', 'cols'
23
24
  ],
24
25
  ALLOW_DATA_ATTR: true,
25
26
  FORBID_ATTR: ['onerror', 'onload', 'onclick', 'onmouseover', 'onfocus', 'onblur', 'onchange'],
26
- FORBID_TAGS: ['script', 'iframe', 'object', 'embed', 'form', 'input', 'button', 'meta', 'link'],
27
+ FORBID_TAGS: ['script', 'object', 'embed', 'meta', 'link'],
27
28
  SAFE_URL_PATTERN: /^(https?:|mailto:|tel:|data:image\/)/i
28
29
  }
29
30
 
@@ -38,7 +39,7 @@ const SAFE_FOR_APP = {
38
39
  * ------------------------------------------- */
39
40
  const resolveDefaultMode = () => {
40
41
  try {
41
- const mode = SpyneAppProperties?.mode
42
+ const mode = SpyneAppProperties?.mode || process?.env?.NODE_ENV
42
43
  if (mode === 'authoring' || mode === 'development') return 'richtext'
43
44
  } catch (e) {
44
45
  // Fallback: assume production strict mode
@@ -48,6 +49,10 @@ const resolveDefaultMode = () => {
48
49
 
49
50
  /* --------------------------------------------- */
50
51
  function makeSanitizeFn(mode = 'app') {
52
+ if (process?.env?.NODE_ENV === 'development') {
53
+ mode = 'richtext'
54
+ }
55
+
51
56
  const cfg = mode === 'richtext' ? SAFE_FOR_RICH_TEXT : SAFE_FOR_APP
52
57
 
53
58
  return (html) => {
@@ -57,7 +62,7 @@ function makeSanitizeFn(mode = 'app') {
57
62
  if (mode === 'richtext') {
58
63
  clean = clean.replace(/<(a|img)\b([^>]+?)>/gi, (match) => {
59
64
  return match.replace(/\b(href|src)="([^"]*)"/gi, (m, attr, val) => {
60
- return SAFE_FOR_RICH_TEXT.SAFE_URL_PATTERN.test(val) ? m : `${attr}=""`
65
+ return m
61
66
  })
62
67
  })
63
68
  }
@@ -114,6 +119,7 @@ const sanitizeData = (data, opts = {}) => {
114
119
  if (!isConfigured) {
115
120
  throw new Error('sanitizeData is not configured. Call sanitizeDataConfigure() first.')
116
121
  }
122
+ // return data;
117
123
  return _sanitizeData(data, opts)
118
124
  }
119
125
 
@@ -135,8 +141,8 @@ const sanitizeEventTarget = (el, mode) => {
135
141
  if (!el) return
136
142
  const effectiveMode = mode || resolveDefaultMode()
137
143
  const sanitizeStr = makeSanitizeFn(effectiveMode)
138
- const UNSAFE_RE = /<(?:script|iframe|object|embed|form|input|button|link|meta)[^>]*>|on\w+=|javascript:/i
139
-
144
+ // const UNSAFE_RE = /<(?:script|iframe|object|embed|form|input|button|link|meta)[^>]*>|on\w+=|javascript:/i
145
+ const UNSAFE_RE = /<(?:script|object|embed|form|input|button|link|meta)[^>]*>|on\w+=|javascript:/i
140
146
  if (typeof el.value === 'string' && UNSAFE_RE.test(el.value)) {
141
147
  const clean = sanitizeStr(el.value)
142
148
  if (clean !== el.value) el.value = clean
@@ -277,62 +277,10 @@ class SpyneAppPropertiesClass {
277
277
  }
278
278
 
279
279
  setCMSProxyMethod(fn){
280
- // this.formatTemplateForProxyData = fn;
281
280
  this.enableCMSProxies = true;
282
- }
283
-
284
- // SpyneJS Enterprise Code Start
285
- formatTemplateForProxyData(tmpl) {
286
- const isPrimitiveTag = str => /({{\.\*?}})/.test(str);
287
-
288
- const reLines2 = /(({{(?!loopNum|loopIndex))(.*?)(}}))/gm
289
- const reStr = '(?<=>)(.*?)(({{)(.*)(}}))'
290
-
291
- const reLines1 = new RegExp(reStr, 'gm')
292
-
293
- const formatCmsParam = (str) => {
294
- const isArrPrimitive = isPrimitiveTag(str)
295
-
296
- const getKeyAndDataId = (s) => {
297
- const re = /({{)([\w_]+(\.))*?(\w+)(}})/gm // this is old, will be deprecated.
298
- const reNestedData = /^\{\{([^}]+?)\.[^.}]+}}$/gm
299
-
300
- let dataId = '__cms__dataId'
301
- const key = isArrPrimitive ? '{{loopIndex}}' : String(s).replace(re, '$4')
302
- if (/(\w\.)/.test(s)) {
303
- dataId = String(s).replace(reNestedData, '$1.') + dataId
304
- }
305
- return { key, dataId }
306
- }
307
-
308
- const { key, dataId } = getKeyAndDataId(str)
281
+ this.formatTemplateForProxyData = fn;
309
282
 
310
- let prefix = `<spyne-cms-item data-cms-id="{{${dataId}}}" data-cms-key="${key}"`
311
-
312
- // IF AN ARRAY PRIMITIVE CHECK FOR ORIGINAL ARRAY POSITION
313
- if (isArrPrimitive) {
314
- prefix += ' data-cms-orig-key="{{origKey}}"'
315
- }
316
-
317
- // CREATE PROXY TAG
318
- const suffix = '</spyne-cms-item>'
319
- const param = isArrPrimitive ? '{{spyneLoopKey}}' : str
320
- return `${prefix}><spyne-cms-item-hitbox></spyne-cms-item-hitbox><spyne-cms-item-text>${param}</spyne-cms-item-text>${suffix}`
321
- }
322
-
323
- const reSwapTags = (str, m1, m2, m3) => {
324
- return formatCmsParam(str)
325
- }
326
-
327
- const reMethod = (str, m1, m2, m3, m4) => {
328
- const m2Updated = String(m2).replace(reLines2, reSwapTags)
329
- return `${m1}${m2Updated}`
330
- }
331
-
332
- return String(tmpl).replace(reLines1, reMethod)
333
283
  }
334
- // SpyneJS Enterprise Code End
335
-
336
284
 
337
285
  tempGetChannelsInstance() {
338
286
 
@@ -2,153 +2,16 @@ import { includes, __, ifElse, path, prop, reject, is, isNil, isEmpty } from 'ra
2
2
  import sanitizeHTML from '../utils/sanitize-html.js'
3
3
  import { SpyneAppProperties } from '../utils/spyne-app-properties.js'
4
4
 
5
- /**
6
- * @module DomElTemplate
7
- * @type util
8
- *
9
- * @constructor
10
- * @param {String|HTMLElement} template
11
- * @param {Object} data
12
- *
13
- * @desc DomElement uses this class when rendering templates.
14
- *
15
- * @example
16
- * TITLE["<h4>Accessing properties using a double bracket {{&nbsp;&nbsp;&nbsp;}} expression</h4>"]
17
- * const data = {{name:"World}};
18
- * const template = `<p>Hello {{name}}!</p>`;
19
- *
20
- * this.props.el.appendChild(new
21
- * DocElTemplate(template,data).renderDocFrag());
22
- *
23
- * // Outputs
24
- * <p>Hello World!</p>
25
- *
26
- *
27
- *
28
- * @example
29
- * TITLE["<h4>Looping through an an array of objects using loop {{#loopProperty}} {{property}} {{/loopProperty}} expression</h4>"]
30
- * const data = {animals: [
31
- * {animal: 'cat', sound: 'meow'},
32
- * {animal: 'dog', sound: 'woof'},
33
- * {animal: 'bird', sound: tweet'}
34
- * ]};
35
- *
36
- * const template = `
37
- * <ul>
38
- * {{#animals}}
39
- * <li>The {{animal}} says '{{sound}}'.</li>
40
- * {{/animals}}
41
- * </ul>`;
42
- *
43
- * this.props.el.appendChild(new
44
- * DocElTemplate(template,data).renderDocFrag());
45
- *
46
- * // Outputs
47
- * <ul>
48
- * <li>The cat says 'meow'.</li>
49
- * <li>The dog says 'woof'.</li>
50
- * <li>The bird says 'tweet'.</li>
51
- * </ul>
52
- *
53
- *
54
- *
55
- * @example
56
- * TITLE["<h4>Looping through list items in an array of using {{#arrName}} &nbsp;&nbsp;{{.}}&nbsp;&nbsp; {{/arrName}} expression</h4>"]
57
- * const data = {name: 'Jane', pets: ['Milo','Luna','Kiki']};
58
- * const template = "<article>
59
- * <h3>Welcome, {{name}}, your pets are:</h3>
60
- * <ul>{{#pets}}
61
- * <li>{{.}}, </li>
62
- * {{/pets}}
63
- * </ul></article>";
64
- *
65
- * this.props.el.appendChild(new
66
- * DocElTemplate(template,data).renderDocFrag());
67
- *
68
- * // Outputs
69
- * <article>
70
- * <h3>Welcome Jane, your pets are:</h3>
71
- * <ul>
72
- * <li>Milo</li>
73
- * <li>Luna</li>
74
- * <li>Kiki</li>
75
- * </ul>
76
- * </article>
77
- *
78
- *
79
- * @example
80
- * TITLE["<h4>Looping through an array with no property name using {{#}} &nbsp;&nbsp;{{ }}&nbsp;&nbsp; {{/}} expression</h4>"]
81
- * const data = [
82
- * {item: 'Cookie', calories: 142},
83
- * {item: 'Apple', calories: 95},
84
- * {item: 'Cheese', calories: 113}];
85
- *
86
- * const template = `
87
- * <article>
88
- * <h3>Snacks:</h3>
89
- * <ul>
90
- * {{#}}
91
- * <li>{{item}}, calories: {{calories}}</li>
92
- * {{/}}
93
- * </ul>
94
- * </article>
95
- * `;
96
- *
97
- * this.props.el.appendChild(new
98
- * DocElTemplate(template,data).renderDocFrag());
99
- *
100
- * // Outputs
101
- * <article>
102
- * <h3>Snacks</h3>
103
- * <ul>
104
- * <li>Cookie, calories: 142</li>
105
- * <li>Apple, calories: 95</li>
106
- * <li>Cheese, calories: 113</li>
107
- * </ul>
108
- * </article>
109
- *
110
- *
111
- * @example
112
- * TITLE["<h4>Looping through an array with no property name using {{#}} &nbsp;&nbsp;{{ . }}&nbsp;&nbsp; {{/}} expression</h4>"]
113
- * const data = ['Tyrion', 'Arya', 'Jon Snow', 'Sansa'];
114
- * const template = `
115
- * <h3>Main GoT Characters</h3>
116
- * <ul>
117
- * {{#}}
118
- * <li>{{.}}</li>
119
- * {{/}}
120
- * </ul>';
121
- *
122
- * this.props.el.appendChild(new
123
- * DocElTemplate(template,data).renderDocFrag());
124
- *
125
- * //Outputs
126
- * <h3>Main GoT Characters</h3>
127
- * <ul>
128
- * <li>Tyrion</li>
129
- * <li>Arya</li>
130
- * <li>Jon Snow</li>
131
- * <li>Sansa</li>
132
- * </ul>
133
- *
134
- *
135
- */
136
-
137
5
  export class DomElementTemplate {
138
6
  constructor(template, data = {}, opts = {}) {
139
7
  this.template = this.formatTemplate(template)
140
8
  this.isProxyData = data.__cms__isProxy === true
141
9
  this.testMode = opts?.testMode
142
10
 
143
- /*
144
11
  if (this.isProxyData === true) {
145
- console.log('PROXY IS ', data.__cms__rootData)
146
- this.template = DomElementTemplate.formatTemplateForProxyData(this.template)
147
- }
148
- */
149
-
150
- if (SpyneAppProperties.enableCMSProxies && this.isProxyData === true) {
151
- this.template = SpyneAppProperties.formatTemplateForProxyData(this.template)
12
+ if (SpyneAppProperties.enableCMSProxies === true) {
13
+ this.template = SpyneAppProperties.formatTemplateForProxyData(this.template)
14
+ }
152
15
  }
153
16
 
154
17
  const checkForArrayData = () => {
@@ -237,7 +100,6 @@ export class DomElementTemplate {
237
100
 
238
101
  renderDocFrag() {
239
102
  let html = DomElementTemplate.replaceImgPath(this.finalArr.join(''))
240
- // html = sanitizeHTML(this.finalArr.join(''))
241
103
  if (this.testMode !== true) {
242
104
  html = sanitizeHTML(html)
243
105
  }
@@ -286,24 +148,15 @@ export class DomElementTemplate {
286
148
  }
287
149
 
288
150
  parseTheTmplLoop(str, p1, p2, p3) {
289
- // const dotConverter = str => `${str.replace(/(\.)/g, '][')}`
290
151
  const reDot = /(\.)/gm
291
152
  const subStr = p3
292
-
293
- /* const dataReducer = (acc, str) => {
294
- acc = acc[str]
295
- return acc
296
- } */
297
-
298
153
  let elData = DomElementTemplate.getNestedDataReducer(this.templateData, p2)
299
154
 
300
155
  const arrayStringToObjAdapter = (d, str, i) => {
301
- // IF {{.}} RUN parseString
302
156
  if (DomElementTemplate.isPrimitiveTag(str)) {
303
157
  return parseString(d, str, i)
304
158
  }
305
159
 
306
- // CREATE DATA OBJ -- CHECK TO ADD PROXY VALUES
307
160
  const createDataObj = () => {
308
161
  const spyneLoopKey = d
309
162
  const loopIndex = i
@@ -1,14 +1,12 @@
1
1
  import { DomElementTemplate } from '../../spyne/views/dom-element-template';
2
2
 
3
- // Evaluate once at the top
4
- const isPublic = process.env.IS_PUBLIC === true;
5
-
6
- console.log("IS PUBLIC ",isPublic);
7
-
8
-
9
- // If not public, skip this test suite altogether
10
- (isPublic ? describe : describe.skip)('DomElementTemplate Proxy (Public Test)', () => {
11
- it('should not have a proxy method', () => {
12
- expect(DomElementTemplate.hasOwnProperty('formatTemplateForProxyData')).to.be.false;
3
+ describe('DomElementTemplate (Public)', () => {
4
+ it('does not expose CMS proxy functionality', () => {
5
+ expect(
6
+ Object.prototype.hasOwnProperty.call(
7
+ DomElementTemplate,
8
+ 'formatTemplateForProxyData'
9
+ )
10
+ ).to.be.false;
13
11
  });
14
12
  });