@burger-editor/frozen-patty 0.11.0 → 4.0.0-alpha.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/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # frozen-patty
2
2
 
3
- [![npm version](https://badge.fury.io/js/%burger-editor%2Ffrozen-patty.svg)](https://badge.fury.io/js/%burger-editor%2Ffrozen-patty) [![Build Status](https://travis-ci.org/YusukeHirao/frozen-patty.svg?branch=master)](https://travis-ci.org/YusukeHirao/frozen-patty) [![Coverage Status](https://coveralls.io/repos/github/YusukeHirao/frozen-patty/badge.svg?branch=master)](https://coveralls.io/github/YusukeHirao/frozen-patty?branch=master)
3
+ [![npm version](https://badge.fury.io/js/@burger-editor%2Ffrozen-patty.svg)](https://badge.fury.io/js/@burger-editor%2Ffrozen-patty)
4
4
 
5
5
  Pure HTML to JSON converter that not use template engine.
6
6
 
@@ -15,52 +15,52 @@ $ npm install -D @burger-editor/frozen-patty
15
15
  ### Extraction
16
16
 
17
17
  ```js
18
- import FrozenPatty from 'frozen-patty';
18
+ import frozenPatty from '@burger-editor/frozen-patty';
19
19
 
20
- FrozenPatty('<div data-field="text">value</div>').toJSON(); // => { text: 'value' }
21
- FrozenPatty('<div data-field="field-name">value</div>').toJSON(); // => { 'field-name': 'value' }
22
- FrozenPatty('<a href="http://localhost" data-field="href:href">link</a>').toJSON(); // => { 'href': 'http://localhost' }
20
+ frozenPatty('<div data-field="text">value</div>').toJSON(); // => { text: 'value' }
21
+ frozenPatty('<div data-field="field-name">value</div>').toJSON(); // => { 'field-name': 'value' }
22
+ frozenPatty('<a href="http://localhost" data-field="href:href">link</a>').toJSON(); // => { 'href': 'http://localhost' }
23
23
 
24
- FrozenPatty('<div data-bge="text">value</div>', { attr: 'bge' }).toJSON(); // => { text: 'value' }
24
+ frozenPatty('<div data-bge="text">value</div>', { attr: 'bge' }).toJSON(); // => { text: 'value' }
25
25
  ```
26
26
 
27
27
  ### Data merge
28
28
 
29
29
  ```js
30
- FrozenPatty('<div data-field="text">value</div>').merge({ text: 'merged' }).toHTML(); // => "<div data-field="text">merged</div>";
30
+ frozenPatty('<div data-field="text">value</div>').merge({ text: 'merged' }).toHTML(); // => "<div data-field="text">merged</div>";
31
31
  ```
32
32
 
33
33
  ## API
34
34
 
35
- ### FrozenPatty (html[, options])
35
+ ### `frozenPatty(html[, options])`
36
36
 
37
37
  Extraction data from HTML.
38
38
 
39
- #### arguments
39
+ #### Parameters
40
40
 
41
- | args | type | required | descriptions |
42
- | ------- | -------- | -------- | ------------- |
43
- | html | `string` | required | Original HTML |
44
- | options | `Object` | optional | † |
41
+ | parameter | type | required | descriptions |
42
+ | --------- | -------- | -------- | ------------- |
43
+ | html | `string` | required | Original HTML |
44
+ | options | `Object` | optional | † |
45
45
 
46
- #### options†
46
+ #### Options†
47
47
 
48
48
  | options | type | default | descriptions |
49
49
  | ------- | ------ | --------- | ------------------------------------------------------------------------------------ |
50
50
  | attr | string | `"field"` | **Data attribute** name for specifying the node that FrozenPatty treats as a _field_ |
51
51
 
52
- ### merge (data)
52
+ ### `merge(data)`
53
53
 
54
- Data merge
54
+ Merge data.
55
55
 
56
56
  | args | type | required | descriptions |
57
57
  | ---- | -------- | -------- | ------------ |
58
58
  | data | `Object` | required | New data |
59
59
 
60
- ### toJSON
60
+ ### `toJSON`
61
61
 
62
- Data to plain Object.
62
+ Convert to JSON.
63
63
 
64
- ### toHTML
64
+ ### `toHTML`
65
65
 
66
- Render to HTML as string.
66
+ Convert to HTML string.
@@ -0,0 +1,8 @@
1
+ /**
2
+ *
3
+ * @param field
4
+ */
5
+ export declare function fieldNameParser(field: string): {
6
+ fieldName: string;
7
+ propName: string;
8
+ };
@@ -0,0 +1,18 @@
1
+ import { camelCase } from './utils.js';
2
+ /**
3
+ *
4
+ * @param field
5
+ */
6
+ export function fieldNameParser(field) {
7
+ field = field.trim().toLowerCase();
8
+ if (!field) {
9
+ throw new Error('Field name is empty.');
10
+ }
11
+ let [fieldName, propName] = field.split(':');
12
+ propName = propName?.trim() || '';
13
+ fieldName = fieldName?.trim() || propName || field;
14
+ return {
15
+ fieldName: camelCase(fieldName),
16
+ propName,
17
+ };
18
+ }
@@ -15,7 +15,6 @@ export default class FrozenPatty {
15
15
  export interface FrozenPattyOptions {
16
16
  /**
17
17
  * **Data attribute** name for specifying the node that FrozenPatty treats as a _field_
18
- *
19
18
  * @default `"field"`
20
19
  */
21
20
  attr?: string;
@@ -28,7 +27,6 @@ export interface FrozenPattyOptions {
28
27
  * - `"1"` => `1`
29
28
  * - `"1.0"` => `1`
30
29
  * - `"0.1"` => `0.1`
31
- *
32
30
  * @default `false`
33
31
  */
34
32
  typeConvert?: boolean;
@@ -1,10 +1,10 @@
1
1
  import type { Filter, PrimitiveDatum } from './types.js';
2
2
  /**
3
3
  * Get value from an element
4
- *
5
4
  * @param el A target element
6
5
  * @param name A label name
7
6
  * @param typeConvert Auto covert type of value
8
7
  * @param attr Data attribute name for specifying the node that FrozenPatty treats as a field
8
+ * @param filter
9
9
  */
10
10
  export declare function getValue(el: Element, name: string, typeConvert?: boolean, attr?: string, filter?: Filter): PrimitiveDatum | PrimitiveDatum[];
package/dist/get-value.js CHANGED
@@ -2,11 +2,11 @@ import { getValues } from './get-values.js';
2
2
  import { arrayToHash } from './utils.js';
3
3
  /**
4
4
  * Get value from an element
5
- *
6
5
  * @param el A target element
7
6
  * @param name A label name
8
7
  * @param typeConvert Auto covert type of value
9
8
  * @param attr Data attribute name for specifying the node that FrozenPatty treats as a field
9
+ * @param filter
10
10
  */
11
11
  export function getValue(el, name, typeConvert = false, attr = 'field', filter) {
12
12
  const value = getValues(el, typeConvert, attr, filter);
@@ -1,10 +1,9 @@
1
1
  import type { Filter, PrimitiveDatum } from './types.js';
2
2
  /**
3
3
  * Get value from an element
4
- *
5
4
  * @param el A target element
6
- * @param name A label name
7
- * @param typeConvert Auto covert type of value
5
+ * @param convertType Auto covert type of value
8
6
  * @param attr Data attribute name for specifying the node that FrozenPatty treats as a field
7
+ * @param filter
9
8
  */
10
- export declare function getValues(el: Element, typeConvert?: boolean, attr?: string, filter?: Filter): [string | number, PrimitiveDatum, boolean][];
9
+ export declare function getValues(el: Element, convertType?: boolean, attr?: string, filter?: Filter): [key: string | number, value: PrimitiveDatum, forceArray: boolean][];
@@ -1,15 +1,13 @@
1
+ import { fieldNameParser } from './field-name-parser.js';
2
+ import { kebabCase } from './utils.js';
1
3
  /**
2
4
  * Get value from an element
3
- *
4
5
  * @param el A target element
5
- * @param name A label name
6
- * @param typeConvert Auto covert type of value
6
+ * @param convertType Auto covert type of value
7
7
  * @param attr Data attribute name for specifying the node that FrozenPatty treats as a field
8
+ * @param filter
8
9
  */
9
- export function getValues(el, typeConvert = false, attr = 'field', filter) {
10
- /**
11
- * [key, value, forceArray]
12
- */
10
+ export function getValues(el, convertType = false, attr = 'field', filter) {
13
11
  const result = [];
14
12
  const rawValue = el.getAttribute(`data-${attr}`);
15
13
  const listRoot = el.closest(`[data-${attr}-list]`);
@@ -17,65 +15,73 @@ export function getValues(el, typeConvert = false, attr = 'field', filter) {
17
15
  if (rawValue == null) {
18
16
  throw new Error(`data-${attr} attriblute is empty.`);
19
17
  }
20
- const fieldList = `${rawValue}`.split(/\s*,\s*/);
21
- // console.log({fieldList, el: el.innerHTML});
22
- for (let fieldName of fieldList) {
23
- let splitKey;
24
- let keyAttr = '';
18
+ const fieldList = rawValue.split(/\s*,\s*/);
19
+ for (const field of fieldList) {
25
20
  let value;
26
- fieldName = fieldName.trim();
27
- if (/^[_a-z-][\w-]*:[_a-z-][\w-]*(?:\([a-z-]+\))?/i.test(fieldName)) {
28
- splitKey = fieldName.split(':');
29
- fieldName = splitKey[0]?.trim() ?? '';
30
- keyAttr = splitKey[1]?.trim() ?? '';
31
- }
32
- // console.log({fieldName, keyAttr, el: el.innerHTML});
33
- if (keyAttr === 'text') {
34
- value = el.innerHTML;
35
- }
36
- else if (/^style\([a-z-]+\)$/i.test(keyAttr)) {
37
- const css = keyAttr.replace(/^style\(([a-z-]+)\)$/i, '$1');
38
- let style;
39
- if (el instanceof HTMLElement) {
40
- style = el.style;
41
- }
42
- else {
43
- style = window.getComputedStyle(el);
44
- }
45
- value = style.getPropertyValue(css);
46
- if (css === 'background-image') {
47
- value = getBackgroundImagePath(value);
21
+ const { fieldName, propName } = fieldNameParser(field);
22
+ if (propName) {
23
+ switch (propName) {
24
+ case 'node': {
25
+ value = el.localName ?? el.nodeName.toLowerCase();
26
+ break;
27
+ }
28
+ case 'text': {
29
+ value = el.textContent?.trim() ?? '';
30
+ break;
31
+ }
32
+ case 'html': {
33
+ value = el.innerHTML.trim();
34
+ break;
35
+ }
36
+ default: {
37
+ if (/^style\([a-z-]+\)$/i.test(propName)) {
38
+ const css = propName.replace(/^style\(([a-z-]+)\)$/i, '$1');
39
+ let style;
40
+ if (el instanceof HTMLElement) {
41
+ style = el.style;
42
+ }
43
+ else {
44
+ style = window.getComputedStyle(el);
45
+ }
46
+ value = style.getPropertyValue(css);
47
+ if (css === 'background-image') {
48
+ value = getBackgroundImagePath(value);
49
+ }
50
+ break;
51
+ }
52
+ value = getAttribute(el, attr, propName, convertType);
53
+ }
48
54
  }
49
55
  }
50
- else if (keyAttr) {
51
- value = getAttribute(el, keyAttr, typeConvert);
52
- }
53
56
  else {
54
57
  if (el instanceof HTMLInputElement ||
55
58
  el instanceof HTMLSelectElement ||
56
59
  el instanceof HTMLTextAreaElement) {
57
60
  const val = el.value;
58
- if (Array.isArray(val)) {
59
- value = cast(val[0]);
60
- }
61
- else {
62
- value = cast(val);
63
- }
61
+ value = convertType ? convert(val) : val;
64
62
  }
65
63
  else {
66
- value = el.innerHTML;
64
+ value = el.innerHTML.trim();
67
65
  }
68
66
  }
69
- // console.log({fieldName, value});
70
67
  if (filter) {
71
68
  value = filter(value);
72
69
  }
70
+ if (value === undefined) {
71
+ continue;
72
+ }
73
73
  result.push([fieldName, value, forceArray]);
74
74
  }
75
- // console.log({result});
76
75
  return result;
77
76
  }
78
- function getAttribute(el, keyAttr, typeConvert) {
77
+ /**
78
+ *
79
+ * @param el
80
+ * @param attr
81
+ * @param keyAttr
82
+ * @param typeConvert
83
+ */
84
+ function getAttribute(el, attr, keyAttr, typeConvert) {
79
85
  switch (keyAttr) {
80
86
  case 'contenteditable': {
81
87
  if (el instanceof HTMLElement) {
@@ -98,41 +104,53 @@ function getAttribute(el, keyAttr, typeConvert) {
98
104
  }
99
105
  case 'href': {
100
106
  // return (el as HTMLAnchorElement).href;
101
- return el.getAttribute(keyAttr) || ''; // return plain string
107
+ return el.getAttribute(keyAttr) ?? ''; // return plain string
102
108
  }
103
109
  default: {
104
- if (keyAttr.startsWith('data-')) {
105
- const value = el.getAttribute(keyAttr) || '';
106
- if (typeConvert) {
107
- return cast(value);
108
- }
109
- return value;
110
+ let value;
111
+ const dataAttr = ['data', attr, kebabCase(keyAttr)].join('-');
112
+ if (el.hasAttribute(dataAttr)) {
113
+ value = el.getAttribute(dataAttr) || '';
114
+ }
115
+ else {
116
+ value = el.getAttribute(keyAttr) || '';
110
117
  }
111
- return el.getAttribute(keyAttr) || '';
118
+ if (typeConvert) {
119
+ value = convert(value);
120
+ }
121
+ return value;
112
122
  }
113
123
  }
114
124
  }
115
- function cast(value) {
116
- if (value == null || value === '') {
117
- return '';
118
- }
119
- switch (value) {
120
- case 'true': {
121
- return true;
122
- }
123
- case 'false': {
124
- return false;
125
+ /**
126
+ *
127
+ * @param value
128
+ */
129
+ function convert(value) {
130
+ value = parse(value);
131
+ if (URL.canParse(value)) {
132
+ const url = new URL(value, location.href);
133
+ if (url.origin === location.origin) {
134
+ return url.pathname;
125
135
  }
126
136
  }
127
- const numeric = Number(value);
128
- if (Number.isFinite(numeric)) {
129
- return numeric;
130
- }
131
137
  return value;
132
138
  }
133
139
  /**
134
- * Get path from value of "background-image"
135
140
  *
141
+ * @param value
142
+ */
143
+ function parse(value) {
144
+ try {
145
+ return JSON.parse(value);
146
+ }
147
+ catch {
148
+ return value;
149
+ }
150
+ }
151
+ /**
152
+ * Get path from value of "background-image"
153
+ * @param value
136
154
  */
137
155
  function getBackgroundImagePath(value) {
138
156
  const origin = `${location.protocol}//${location.hostname}${location.port ? `:${location.port}` : ''}`;
package/dist/get.d.ts CHANGED
@@ -1,2 +1,9 @@
1
1
  import type { Filter, FrozenPattyData } from './types.js';
2
+ /**
3
+ *
4
+ * @param el
5
+ * @param attr
6
+ * @param typeConvert
7
+ * @param filter
8
+ */
2
9
  export default function (el: Element, attr: string, typeConvert: boolean, filter?: Filter): FrozenPattyData;
package/dist/get.js CHANGED
@@ -1,5 +1,12 @@
1
1
  import { getValues } from './get-values.js';
2
2
  import { arrayToHash } from './utils.js';
3
+ /**
4
+ *
5
+ * @param el
6
+ * @param attr
7
+ * @param typeConvert
8
+ * @param filter
9
+ */
3
10
  export default function (el, attr, typeConvert, filter) {
4
11
  // eslint-disable-next-line unicorn/prefer-spread
5
12
  const filedElements = Array.from(el.querySelectorAll(`[data-${attr}]`));
package/dist/index.d.ts CHANGED
@@ -2,8 +2,12 @@ import type { FrozenPattyOptions } from './frozen-patty.js';
2
2
  import FrozenPatty from './frozen-patty.js';
3
3
  /**
4
4
  * Pure HTML to JSON converter that not use template engine.
5
- *
6
5
  * @param html Original HTML
7
6
  * @param options Options
8
7
  */
8
+ /**
9
+ *
10
+ * @param html
11
+ * @param options
12
+ */
9
13
  export default function frozenPatty(html: string, options?: FrozenPattyOptions): FrozenPatty;
package/dist/index.js CHANGED
@@ -1,10 +1,14 @@
1
1
  import FrozenPatty from './frozen-patty.js';
2
2
  /**
3
3
  * Pure HTML to JSON converter that not use template engine.
4
- *
5
4
  * @param html Original HTML
6
5
  * @param options Options
7
6
  */
7
+ /**
8
+ *
9
+ * @param html
10
+ * @param options
11
+ */
8
12
  export default function frozenPatty(html, options) {
9
13
  return new FrozenPatty(html, options);
10
14
  }
@@ -5,10 +5,17 @@ import type { Filter, PrimitiveDatum } from './types.js';
5
5
  * ```html
6
6
  * <div [target-attribute] data-[attr]="[name]:[target-attribute]"></div>
7
7
  * ```
8
- *
9
8
  * @param el A target element
10
9
  * @param name A label name
11
10
  * @param datum A datum of value
12
11
  * @param attr Data attribute name for specifying the node that FrozenPatty treats as a field
12
+ * @param filter
13
13
  */
14
14
  export declare function setValue(el: Element, name: string, datum: PrimitiveDatum, attr?: string, filter?: Filter): void;
15
+ /**
16
+ *
17
+ * @param el
18
+ * @param datum
19
+ * @param asHtml
20
+ */
21
+ export declare function setContent(el: Element, datum: PrimitiveDatum, asHtml?: boolean): void;