aleman 1.0.0

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.
Files changed (36) hide show
  1. package/README.md +23 -0
  2. package/index.html +25 -0
  3. package/lib/addons/input-change.js +38 -0
  4. package/lib/addons/menu-click.js +9 -0
  5. package/lib/addons/start-click.js +7 -0
  6. package/lib/addons/stop-click.js +7 -0
  7. package/lib/aleman/add-listeners.js +94 -0
  8. package/lib/aleman/aleman.js +23 -0
  9. package/lib/aleman/load.js +10 -0
  10. package/lib/aleman/render.js +88 -0
  11. package/lib/globals/menu-next.js +20 -0
  12. package/lib/main.js +24 -0
  13. package/lib/rules/README.md +6 -0
  14. package/lib/rules/index.js +11 -0
  15. package/lib/rules/menu/fixture/hide-menu-fix.js +1 -0
  16. package/lib/rules/menu/fixture/hide-menu.js +1 -0
  17. package/lib/rules/menu/fixture/no-menu.js +3 -0
  18. package/lib/rules/menu/fixture/show-menu-fix.js +1 -0
  19. package/lib/rules/menu/fixture/show-menu.js +1 -0
  20. package/lib/rules/menu/index.js +59 -0
  21. package/lib/rules/menu/index.spec.js +34 -0
  22. package/lib/rules/remove-button/fixture/remove-button-fix.js +2 -0
  23. package/lib/rules/remove-button/fixture/remove-button.js +2 -0
  24. package/lib/rules/remove-button/index.js +27 -0
  25. package/lib/rules/remove-button/index.spec.js +20 -0
  26. package/lib/rules/select-next/fixture/select-next-fix.js +8 -0
  27. package/lib/rules/select-next/fixture/select-next.js +8 -0
  28. package/lib/rules/select-next/index.js +69 -0
  29. package/lib/rules/select-next/index.spec.js +18 -0
  30. package/lib/rules/set-value/fixture/data-name.js +1 -0
  31. package/lib/rules/set-value/fixture/set-value-fix.js +1 -0
  32. package/lib/rules/set-value/fixture/set-value.js +1 -0
  33. package/lib/rules/set-value/index.js +34 -0
  34. package/lib/rules/set-value/index.spec.js +29 -0
  35. package/package.json +52 -0
  36. package/style.css +65 -0
package/README.md ADDED
@@ -0,0 +1,23 @@
1
+ # Aleman
2
+
3
+ ![image](https://github.com/user-attachments/assets/32b3499d-1490-43d3-bdd1-84d646432c82)
4
+
5
+ > **ぶしどうとはしぬこととみつけたり。**
6
+ >
7
+ > *Bushidō to wa shinu koto to mitsuketari.*
8
+ >
9
+ > **"The way of the warrior is found in death."**
10
+ >
11
+ > **はがくれ』**
12
+ >
13
+ > Yamamoto Tsunetomo, Hagakure
14
+
15
+ ## Instal
16
+
17
+ ```
18
+ bun i aleman
19
+ ```
20
+
21
+ ## Licence
22
+
23
+ MIT
package/index.html ADDED
@@ -0,0 +1,25 @@
1
+ <!doctype html>
2
+ <link href="style.css" rel="stylesheet">
3
+
4
+ <section data-name="hydrate">
5
+ <button data-name="menu-toggler">Menu</button>
6
+ <button data-name="select-toggler">Select</button>
7
+ <button data-name=start>hello</button>
8
+ <button data-name=stop>world</button>
9
+ <label>
10
+ <input data-name="input"/>
11
+ </label>
12
+ <label data-name="value"></label>
13
+ <ul data-name="menu" class="menu menu-hidden" style="left: 0; top: 20px;">
14
+ <li data-name="js-menu-item" class="menu-item icon icon-view menu-item-selected"><label data-menu-path="View">View</label></li><li data-name="js-menu-item" class="menu-item icon icon-edit"><label data-menu-path="Edit">Edit</label></li><li data-name="js-menu-item" class="menu-item icon icon-rename"><label data-menu-path="Rename">Rename</label></li><li data-name="js-menu-item" class="menu-item icon icon-delete"><label data-menu-path="Delete">Delete</label></li><li data-name="js-menu-item" class="menu-item icon icon-pack"><label data-menu-path="Pack">Pack</label></li><li data-name="js-menu-item" class="menu-item icon icon-extract"><label data-menu-path="Extract">Extract</label></li><li data-name="js-menu-item" class="menu-item icon icon-download"><label data-menu-path="Download">Download</label></li><li data-name="js-menu-item" class="menu-item icon icon-upload-to-cloud"><label data-menu-path="Upload To Cloud">Upload To Cloud</label></li><li data-name="js-menu-item" class="menu-item icon icon-cut"><label data-menu-path="Cut">Cut</label></li><li data-name="js-menu-item" class="menu-item icon icon-copy"><label data-menu-path="Copy">Copy</label></li><li data-name="js-menu-item" class="menu-item icon icon-paste"><label data-menu-path="Paste">Paste</label></li><li data-name="js-menu-item" class="menu-item menu-submenu icon icon-new" data-menu="js-submenu"><label data-menu-path="New">New</label><ul data-name="js-menu" class="menu menu-hidden"><li data-name="js-menu-item" class="menu-item icon icon-file"><label data-menu-path="New.File">File</label></li><li data-name="js-menu-item" class="menu-item icon icon-directory"><label data-menu-path="New.Directory">Directory</label></li></ul></li><li data-name="js-menu-item" class="menu-item icon icon-upload"><label data-menu-path="Upload">Upload</label></li><li data-name="js-menu-item" class="menu-item icon icon-upload-from-cloud"><label data-menu-path="Upload From Cloud">Upload From Cloud</label></li><li data-name="js-menu-item" class="menu-item icon icon-toggle-file-selection"><label data-menu-path="Toggle File Selection">Toggle File Selection</label></li><li data-name="js-menu-item" class="menu-item icon icon-unselect-all"><label data-menu-path="(Un)Select All">(Un)Select All</label></li></ul>
15
+ </section>
16
+
17
+
18
+ <script data-name="aleman" type="module" src="lib/aleman/load.js" data-main="lib/main.js"></script>
19
+ <script type="importmap">
20
+ {
21
+ "imports": {
22
+ "putout": "https://esm.sh/@putout/bundle"
23
+ }
24
+ }
25
+ </script>
@@ -0,0 +1,38 @@
1
+ export const name = 'input';
2
+ export const events = [
3
+ 'keyup',
4
+ 'change',
5
+ ];
6
+
7
+ export const listener = ({render, event, element}) => {
8
+ let {value} = element;
9
+
10
+ const {key} = event;
11
+ const keys = [
12
+ 'Shift',
13
+ 'Meta',
14
+ 'ArrowLeft',
15
+ 'ArrowRight',
16
+ ];
17
+
18
+ if (keys.includes(key))
19
+ return;
20
+
21
+ if (isTextSelected(element) && key === 'Backspace')
22
+ value = '';
23
+
24
+ render('set-value', {
25
+ name: 'value',
26
+ value,
27
+ });
28
+
29
+ element.focus();
30
+ };
31
+
32
+ function isTextSelected(input) {
33
+ if (!input.value)
34
+ return false;
35
+
36
+ return !input.selectionStart && input.selectionEnd === input.value.length;
37
+ }
38
+
@@ -0,0 +1,9 @@
1
+ export const name = 'menu-toggler';
2
+ export const events = ['click'];
3
+ export const listener = ({render, element}) => {
4
+ const command = element.command === 'show' ? 'hide' : 'show';
5
+
6
+ render('menu', {
7
+ command,
8
+ });
9
+ };
@@ -0,0 +1,7 @@
1
+ export const name = 'start';
2
+ export const events = ['click'];
3
+ export const listener = ({render}) => {
4
+ return render('remove-button', {
5
+ name: 'start',
6
+ });
7
+ };
@@ -0,0 +1,7 @@
1
+ export const name = 'stop';
2
+ export const events = ['click'];
3
+ export const listener = ({render}) => {
4
+ return render('remove-button', {
5
+ name: 'stop',
6
+ });
7
+ };
@@ -0,0 +1,94 @@
1
+ const isFn = (a) => typeof a === 'function';
2
+ const {addEventListener} = document;
3
+
4
+ export function addGlobalListeners({render, state, globals, storage}) {
5
+ for (const {events, listener, filter} of globals) {
6
+ for (const event of events) {
7
+ addEventListener(event, createListener({
8
+ filter,
9
+ name: 'document',
10
+ render,
11
+ listener,
12
+ storage,
13
+ state,
14
+ }));
15
+ }
16
+ }
17
+ }
18
+
19
+ const success = () => true;
20
+
21
+ const createListener = ({name, filter = success, state, render, listener, storage}) => (event) => {
22
+ const is = filter({
23
+ event,
24
+ state,
25
+ });
26
+
27
+ if (!is)
28
+ return;
29
+
30
+ listener({
31
+ render: render(name),
32
+ event,
33
+ element: createElement(name, storage),
34
+ state,
35
+ });
36
+ };
37
+
38
+ export function addListeners({render, addons, storage}) {
39
+ for (const {name, events, listener} of addons) {
40
+ for (const event of events) {
41
+ const element = document.querySelector(`[data-name='${name}']`);
42
+
43
+ if (!element)
44
+ continue;
45
+
46
+ element.addEventListener(event, createListener({
47
+ name,
48
+ render,
49
+ listener,
50
+ storage,
51
+ }));
52
+ }
53
+ }
54
+ }
55
+
56
+ const createSet = (name, storage) => (target, key, value) => {
57
+ const element = document.querySelector(`[data-name='${name}']`);
58
+
59
+ if (!element) {
60
+ storage.set(key, value);
61
+ return true;
62
+ }
63
+
64
+ element[key] = value;
65
+
66
+ return true;
67
+ };
68
+
69
+ const createGet = (name, storage) => (target, key) => {
70
+ const element = document.querySelector(`[data-name='${name}']`);
71
+
72
+ if (!element)
73
+ return storage.get(key);
74
+
75
+ const result = element[key];
76
+
77
+ if (!result)
78
+ return element.getAttribute(key) || '';
79
+
80
+ if (isFn(result))
81
+ return result.bind(element);
82
+
83
+ return result;
84
+ };
85
+
86
+ const createElement = (name, storage) => {
87
+ const get = createGet(name, storage);
88
+ const set = createSet(name, storage);
89
+
90
+ return new Proxy({}, {
91
+ get,
92
+ set,
93
+ });
94
+ };
@@ -0,0 +1,23 @@
1
+ import {
2
+ addListeners,
3
+ addGlobalListeners,
4
+ } from './add-listeners.js';
5
+ import {createRender} from './render.js';
6
+
7
+ export const hydrate = ({element, rules, addons, globals}) => {
8
+ element = element || document.querySelector('[data-name="hydrate"]') || document.body;
9
+ const html = `<section>${element.innerHTML}</section>`;
10
+ const storage = new Map();
11
+ const state = {};
12
+
13
+ const render = createRender(html, {
14
+ rules,
15
+ addons,
16
+ element,
17
+ storage,
18
+ state,
19
+ });
20
+
21
+ addListeners({render, addons, storage, state});
22
+ addGlobalListeners({render, globals, storage, state});
23
+ };
@@ -0,0 +1,10 @@
1
+ document.addEventListener('DOMContentLoaded', function load() {
2
+ const loader = document.querySelector('[data-name="aleman"]');
3
+ const el = document.createElement('script');
4
+
5
+ el.src = loader.dataset.main;
6
+ el.type = 'module';
7
+
8
+ document.body.appendChild(el);
9
+ document.removeEventListener('DOMContentLoaded', load);
10
+ });
@@ -0,0 +1,88 @@
1
+ import {
2
+ parse,
3
+ transform,
4
+ print,
5
+ } from 'https://esm.sh/@putout/bundle';
6
+ import {branch, merge} from 'https://esm.sh/@putout/processor-html@14.0.2';
7
+ import {escape} from 'https://esm.sh/html-escaper';
8
+ import {addListeners} from './add-listeners.js';
9
+
10
+ const {isArray} = Array;
11
+ const maybeArray = (a) => isArray(a) ? a : [a];
12
+ const {assign, entries} = Object;
13
+
14
+ export const createRender = (html, {state, storage, rules, addons, element}) => {
15
+ const {source} = branch(html)[0];
16
+ const ast = parse(source);
17
+
18
+ return function render(elementName = 'document') {
19
+ return (names, options = {}) => {
20
+ assign(state, {
21
+ [elementName]: options,
22
+ });
23
+
24
+ assign(options, {
25
+ escape,
26
+ });
27
+
28
+ const plugins = [];
29
+ const currentRules = {};
30
+
31
+ for (const [name, rule] of entries(rules)) {
32
+ for (const currentName of maybeArray(names)) {
33
+ if (name === currentName) {
34
+ plugins.push([name, rule]);
35
+ currentRules[name] = ['on', options];
36
+ }
37
+ }
38
+ }
39
+
40
+ transform(ast, '', {
41
+ rules: currentRules,
42
+ plugins,
43
+ });
44
+
45
+ const code = print(ast, {
46
+ printer: ['putout', {
47
+ format: {
48
+ newline: '',
49
+ endOfFile: '',
50
+ },
51
+ }],
52
+ });
53
+
54
+ const prefix = '<section>';
55
+ const suffix = '<\\section>';
56
+
57
+ element.innerHTML = merge('', [code]).slice(prefix.length, -suffix.length);
58
+ addListeners({
59
+ render,
60
+ addons,
61
+ storage,
62
+ });
63
+ restoreState({
64
+ state,
65
+ element,
66
+ storage,
67
+ });
68
+ };
69
+ };
70
+ };
71
+
72
+ function restoreState({state, element, storage}) {
73
+ for (const [name, options] of entries(state)) {
74
+ const el = element.querySelector(`[data-name='${name}']`);
75
+
76
+ if (!el && name === 'document')
77
+ for (const [key, value] of entries(options)) {
78
+ storage.set(key, value);
79
+ }
80
+
81
+ if (!el) {
82
+ delete state[name];
83
+ continue;
84
+ }
85
+
86
+ assign(el, options);
87
+ }
88
+ }
@@ -0,0 +1,20 @@
1
+ export const events = ['keydown'];
2
+
3
+ export const filter = ({event, state}) => {
4
+ if (event.key !== 'ArrowDown')
5
+ return false;
6
+
7
+ const {command} = state['menu-toggler'] || {
8
+ command: 'show',
9
+ };
10
+
11
+ return command !== 'hide';
12
+ };
13
+ export const listener = ({state, render, element}) => {
14
+ const index = element.index || 0;
15
+
16
+ render('select-next', {
17
+ index: index + 1,
18
+ });
19
+ };
20
+
package/lib/main.js ADDED
@@ -0,0 +1,24 @@
1
+ import * as start from './addons/start-click.js';
2
+ import * as stop from './addons/stop-click.js';
3
+ import * as inputChange from './addons/input-change.js';
4
+ import * as menuClick from './addons/menu-click.js';
5
+ import * as menuNext from './globals/menu-next.js';
6
+ import {hydrate} from './aleman/aleman.js';
7
+ import {rules} from './rules/index.js';
8
+
9
+ const addons = [
10
+ start,
11
+ stop,
12
+ inputChange,
13
+ menuClick,
14
+ ];
15
+
16
+ const globals = [
17
+ menuNext,
18
+ ];
19
+
20
+ hydrate({
21
+ rules,
22
+ addons,
23
+ globals,
24
+ });
@@ -0,0 +1,6 @@
1
+ # HTML
2
+
3
+ - ✅[`set-value`](https://putout.cloudcmd.io/#/gist/29850822bca99f83dbea1b17fda61904/6cdec0ef8c1903cbc9b9df6dfcde6056b8165386);
4
+ - ✅[`remove-button`](https://putout.cloudcmd.io/#/gist/fa2b037a629306cbd43cf42c457c08b9/0cac9c986141d69f9747538816e66b14c4cbd256);
5
+ - ✅[`show-menu`](https://putout.cloudcmd.io/#/gist/884fd40c07b94951de1a9ce99afab015/21d4881b44955b1426f80e87c76b7ad86eeea464);
6
+ - ✅[`select-next`](https://putout.cloudcmd.io/#/gist/10891aa58ff2ecfa1728ed19aeb2e3f2/ce536fb0b414faefbae5d0c8a094517beb1c606e);
@@ -0,0 +1,11 @@
1
+ import * as selectNext from './select-next/index.js';
2
+ import * as menu from './menu/index.js';
3
+ import * as removeButton from './remove-button/index.js';
4
+ import * as setValue from './set-value/index.js';
5
+
6
+ export const rules = {
7
+ 'set-value': setValue,
8
+ 'remove-button': removeButton,
9
+ 'menu': menu,
10
+ 'select-next': selectNext,
11
+ };
@@ -0,0 +1 @@
1
+ <ul data-name="menu" className='menu menu-hidden'><li></li><li></li></ul>;
@@ -0,0 +1 @@
1
+ <ul data-name="menu" className="menu"><li></li><li></li></ul>;
@@ -0,0 +1,3 @@
1
+ <section className="hidden">
2
+ <ul data-name="hello" className="menu"><li></li><li></li></ul>;
3
+ </section>;
@@ -0,0 +1 @@
1
+ <ul data-name="menu" className='menu'><li></li><li></li></ul>;
@@ -0,0 +1 @@
1
+ <ul data-name="menu" className="menu menu-hidden"><li></li><li></li></ul>;
@@ -0,0 +1,59 @@
1
+ import {operator} from 'putout';
2
+
3
+ const {setLiteralValue} = operator;
4
+
5
+ export const report = ({command}) => {
6
+ const [first, ...rest] = command;
7
+
8
+ return `${first.toUpperCase()}${rest.join('')} menu`;
9
+ };
10
+
11
+ export const fix = ({path, command}) => {
12
+ const {value} = path.node;
13
+ let newValue;
14
+
15
+ if (command === 'show')
16
+ newValue = value.value.replace(/\s?menu-hidden/, '');
17
+ else
18
+ newValue = value.value + ' menu-hidden';
19
+
20
+ setLiteralValue(value, newValue);
21
+ };
22
+
23
+ export const traverse = ({push, options}) => ({
24
+ JSXOpeningElement(path) {
25
+ const {command} = options;
26
+ const attributes = path.get('attributes');
27
+
28
+ for (const attr of attributes) {
29
+ const {name, value} = attr.node;
30
+
31
+ if (name.name !== 'data-name')
32
+ continue;
33
+
34
+ if (value.value !== 'menu')
35
+ return;
36
+
37
+ break;
38
+ }
39
+
40
+ for (const attr of attributes) {
41
+ const {name, value} = attr.node;
42
+
43
+ if (name.name !== 'className')
44
+ continue;
45
+
46
+ if (command === 'show' && value.value.includes('menu-hidden'))
47
+ push({
48
+ command: 'show',
49
+ path: attr,
50
+ });
51
+
52
+ if (command === 'hide' && !value.value.includes('menu-hidden'))
53
+ push({
54
+ command,
55
+ path: attr,
56
+ });
57
+ }
58
+ },
59
+ });
@@ -0,0 +1,34 @@
1
+ import {createTest} from '@putout/test';
2
+ import * as plugin from './index.js';
3
+
4
+ const test = createTest(import.meta.url, {
5
+ plugins: [
6
+ ['show-menu', plugin],
7
+ ],
8
+ });
9
+
10
+ test('lib: show-menu: report', (t) => {
11
+ t.reportWithOptions('hide-menu', `Hide menu`, {
12
+ command: 'hide',
13
+ });
14
+ t.end();
15
+ });
16
+
17
+ test('lib: show-menu: transform with options: show-menu', (t) => {
18
+ t.transformWithOptions('show-menu', {
19
+ command: 'show',
20
+ });
21
+ t.end();
22
+ });
23
+
24
+ test('lib: show-menu: transform with options: hide-menu', (t) => {
25
+ t.transformWithOptions('hide-menu', {
26
+ command: 'hide',
27
+ });
28
+ t.end();
29
+ });
30
+
31
+ test('lib: show-menu: no report: no-menu', (t) => {
32
+ t.noReport('no-menu');
33
+ t.end();
34
+ });
@@ -0,0 +1,2 @@
1
+ <button data-name="start">hello</button>;
2
+ <button data-name="stop">hello</button>;
@@ -0,0 +1,2 @@
1
+ <button data-name="start">hello</button>;
2
+ <button data-name="stop">hello</button>;
@@ -0,0 +1,27 @@
1
+ export const report = () => `Remove button`;
2
+
3
+ export const match = ({options}) => ({
4
+ '<button __jsx_attributes>__a</button>': (vars, path) => {
5
+ const defaultName = options.name || '';
6
+ const name = getName(path);
7
+
8
+ return name === defaultName;
9
+ },
10
+ });
11
+
12
+ export const replace = () => ({
13
+ '<button __jsx_attributes>__a</button>': '',
14
+ });
15
+
16
+ function getName(path) {
17
+ const {attributes} = path.node.openingElement;
18
+
19
+ for (const {name, value} of attributes) {
20
+ if (name.name !== 'data-name')
21
+ continue;
22
+
23
+ return value.value;
24
+ }
25
+
26
+ return '';
27
+ }
@@ -0,0 +1,20 @@
1
+ import {createTest} from '@putout/test';
2
+ import * as plugin from './index.js';
3
+
4
+ const test = createTest(import.meta.url, {
5
+ plugins: [
6
+ ['remove-button', plugin],
7
+ ],
8
+ });
9
+
10
+ test('html: remove-button: report', (t) => {
11
+ t.reportWithOptions('remove-button', `Remove button`, {
12
+ name: 'start',
13
+ });
14
+ t.end();
15
+ });
16
+
17
+ test('html: remove-button: transform', (t) => {
18
+ t.transform('remove-button');
19
+ t.end();
20
+ });
@@ -0,0 +1,8 @@
1
+ <ul data-name="menu" class="menu menu-hidden">
2
+ <li data-name="menu-item" class='menu-item icon icon-view'>
3
+ <label data-menu-path="View">View</label>
4
+ </li>
5
+ <li data-name="menu-item" class='menu-item icon icon-edit menu-item-selected'>
6
+ <label data-menu-path="Edit">Edit</label>
7
+ </li>
8
+ </ul>;
@@ -0,0 +1,8 @@
1
+ <ul data-name="menu" class="menu menu-hidden">
2
+ <li data-name="menu-item" class="menu-item icon icon-view menu-item-selected">
3
+ <label data-menu-path="View">View</label>
4
+ </li>
5
+ <li data-name="menu-item" class="menu-item icon icon-edit">
6
+ <label data-menu-path="Edit">Edit</label>
7
+ </li>
8
+ </ul>
@@ -0,0 +1,69 @@
1
+ import {operator, types} from 'putout';
2
+
3
+ const {isJSXElement} = types;
4
+ const {setLiteralValue} = operator;
5
+
6
+ export const report = () => `Select next item`;
7
+
8
+ export const fix = ({path, next}) => {
9
+ const {value} = path.node;
10
+ const newValue = value.value.replace(/\s?menu-item-selected/, '');
11
+
12
+ setLiteralValue(value, newValue);
13
+
14
+ for (const {name, value} of next.node.openingElement.attributes) {
15
+ if (name.name !== 'className')
16
+ continue;
17
+
18
+ setLiteralValue(value, `${value.value} menu-item-selected`);
19
+ }
20
+ };
21
+
22
+ export const traverse = ({options, push}) => ({
23
+ JSXOpeningElement(path) {
24
+ if (path.node.name.name !== 'li')
25
+ return;
26
+
27
+ const {index = 1} = options;
28
+
29
+ const attributes = path.parentPath.parentPath.get('openingElement.attributes');
30
+
31
+ for (const attr of attributes) {
32
+ const {name, value} = attr.node;
33
+
34
+ if (name.name !== 'data-name')
35
+ continue;
36
+
37
+ if (value.value !== 'menu')
38
+ return;
39
+
40
+ break;
41
+ }
42
+
43
+ const children = path.parentPath
44
+ .parentPath
45
+ .get('children')
46
+ .filter(isJSXElement);
47
+
48
+ if (index !== children.indexOf(path.parentPath) + 1)
49
+ return;
50
+
51
+ const next = children[index];
52
+
53
+ if (!next)
54
+ return;
55
+
56
+ for (const attr of path.get('attributes')) {
57
+ const {name, value} = attr.node;
58
+
59
+ if (name.name !== 'className')
60
+ continue;
61
+
62
+ if (value.value.includes('menu-item-selected'))
63
+ push({
64
+ path: attr,
65
+ next,
66
+ });
67
+ }
68
+ },
69
+ });
@@ -0,0 +1,18 @@
1
+ import {createTest} from '@putout/test';
2
+ import * as plugin from './index.js';
3
+
4
+ const test = createTest(import.meta.url, {
5
+ plugins: [
6
+ ['select-next', plugin],
7
+ ],
8
+ });
9
+
10
+ test('lib: select-next: report', (t) => {
11
+ t.report('select-next', `Select next item`);
12
+ t.end();
13
+ });
14
+
15
+ test('lib: select-next: transform', (t) => {
16
+ t.transform('select-next');
17
+ t.end();
18
+ });
@@ -0,0 +1 @@
1
+ <label data-name="hello">x</label>;
@@ -0,0 +1 @@
1
+ <label data-name="x">hello</label>;
@@ -0,0 +1 @@
1
+ <label data-name="x">x</label>;
@@ -0,0 +1,34 @@
1
+ export const report = () => `Use 'if condition' instead of 'ternary expression'`;
2
+
3
+ export const match = ({options}) => {
4
+ const {name} = options;
5
+
6
+ return {
7
+ '<__a __jsx_attributes>__b</__a>': check(name),
8
+ '<__a __jsx_attributes></__a>': check(name),
9
+ };
10
+ };
11
+
12
+ const check = (dataName) => ({__a, __jsx_attributes}) => {
13
+ if (__a.name !== 'label')
14
+ return false;
15
+
16
+ for (const {name, value} of __jsx_attributes) {
17
+ if (name.name !== 'data-name')
18
+ continue;
19
+
20
+ if (value.value === dataName)
21
+ return true;
22
+ }
23
+
24
+ return false;
25
+ };
26
+
27
+ export const replace = ({options}) => {
28
+ const {value = 'hello', escape = (a) => a} = options;
29
+
30
+ return {
31
+ '<__a __jsx_attributes>__b</__a>': `<__a __jsx_attributes>${escape(value)}</__a>`,
32
+ '<__a __jsx_attributes></__a>': `<__a __jsx_attributes>${escape(value)}</__a>`,
33
+ };
34
+ };
@@ -0,0 +1,29 @@
1
+ import {createTest} from '@putout/test';
2
+ import * as plugin from './index.js';
3
+
4
+ const test = createTest(import.meta.url, {
5
+ plugins: [
6
+ ['set-value', plugin],
7
+ ],
8
+ });
9
+
10
+ test('aleman: set-value: report', (t) => {
11
+ t.reportWithOptions('set-value', `Use 'if condition' instead of 'ternary expression'`, {
12
+ name: 'x',
13
+ });
14
+ t.end();
15
+ });
16
+
17
+ test('aleman: set-value: transform with options', (t) => {
18
+ t.transformWithOptions('set-value', {
19
+ name: 'x',
20
+ });
21
+ t.end();
22
+ });
23
+
24
+ test('aleman: set-value: no transform with options: data-name', (t) => {
25
+ t.noTransformWithOptions('data-name', {
26
+ name: 'x',
27
+ });
28
+ t.end();
29
+ });
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "aleman",
3
+ "version": "1.0.0",
4
+ "type": "module",
5
+ "author": "coderaiser <mnemonic.enemy@gmail.com> (https://github.com/coderaiser)",
6
+ "description": "🐊Putout-based framework for web",
7
+ "homepage": "https://github.com/coderaiser/putout/tree/master/packages/plugin-remove-debugger#readme",
8
+ "main": "lib/aleman/aleman.js",
9
+ "release": false,
10
+ "tag": false,
11
+ "changelog": false,
12
+ "repository": {
13
+ "type": "git",
14
+ "url": "git+https://github.com/coderaiser/putout.git"
15
+ },
16
+ "scripts": {
17
+ "test": "madrun test",
18
+ "watch:test": "madrun watch:test",
19
+ "lint": "madrun lint",
20
+ "fresh:lint": "madrun fresh:lint",
21
+ "lint:fresh": "madrun lint:fresh",
22
+ "fix:lint": "madrun fix:lint",
23
+ "coverage": "madrun coverage",
24
+ "report": "madrun report"
25
+ },
26
+ "dependencies": {
27
+ "putout": "^40.5.1"
28
+ },
29
+ "keywords": [
30
+ "putout",
31
+ "putout-plugin",
32
+ "putout-plugin-remove",
33
+ "plugin",
34
+ "debugger"
35
+ ],
36
+ "devDependencies": {
37
+ "@putout/test": "^14.0.0",
38
+ "c8": "^10.0.0",
39
+ "eslint": "^9.0.0",
40
+ "eslint-plugin-n": "^17.0.0",
41
+ "eslint-plugin-putout": "^28.0.0",
42
+ "madrun": "^11.0.0",
43
+ "nodemon": "^3.0.1"
44
+ },
45
+ "license": "MIT",
46
+ "engines": {
47
+ "node": ">=20"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ }
52
+ }
package/style.css ADDED
@@ -0,0 +1,65 @@
1
+ .menu-hidden {
2
+ display: none;
3
+ }
4
+
5
+ .menu {
6
+ position : absolute;
7
+ z-index : 2;
8
+ padding : 0;
9
+ font-size : 14px;
10
+ list-style : none;
11
+ color : #222;
12
+ background : rgb(255 255 255 / 90%);
13
+ border-color : rgb(49 123 249 / 40%);
14
+ border-style : solid;
15
+ border-width : 1px;
16
+ border-radius : 5px;
17
+ -webkit-user-select : none;
18
+ -moz-user-select : none;
19
+ -ms-user-select : none;
20
+ user-select : none;
21
+ }
22
+
23
+ .menu-button {
24
+ background: white;
25
+ border: 0;
26
+ }
27
+
28
+ .menu-item {
29
+ position: relative;
30
+ padding: 3px 20px;
31
+ white-space: pre;
32
+ }
33
+
34
+ .menu-item::after {
35
+ content: attr(data-key);
36
+ float: right;
37
+ }
38
+
39
+ .menu-item:hover, .menu-item-selected {
40
+ background-color: #e3f2ff;
41
+ }
42
+
43
+ .menu-item > .menu {
44
+ top: 0;
45
+ left: 100%;
46
+ display: none;
47
+ }
48
+
49
+ .menu-item:hover > .menu {
50
+ display: block;
51
+ }
52
+
53
+ .menu-submenu > label::after {
54
+ display: block;
55
+ float: right;
56
+ width: 0;
57
+ height: 0;
58
+ margin-top: 3px;
59
+ margin-right: -10px;
60
+ border-color: transparent;
61
+ border-left-color: rgb(49 123 249);
62
+ border-style: solid;
63
+ border-width: 5px 0 5px 5px;
64
+ content: ' ';
65
+ }