nadesiko3 3.7.21 → 3.7.22
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/batch/command.txt +370 -334
- package/batch/jsplugin2text.nako3 +1 -1
- package/batch/pickup_command.nako3 +12 -0
- package/core/command/snako.mts +5 -1
- package/core/deno/snako.ts +5 -1
- package/core/package-lock.json +382 -21
- package/core/package.json +4 -4
- package/core/src/nako3.mts +178 -614
- package/core/src/nako_basic_plugins.mts +39 -0
- package/core/src/nako_core_version.mts +2 -2
- package/core/src/nako_csv.mts +0 -1
- package/core/src/nako_event.mts +49 -0
- package/core/src/nako_gen.mts +291 -202
- package/core/src/nako_indent_inline.mts +2 -2
- package/core/src/nako_lex_rules.mts +1 -1
- package/core/src/nako_parser3.mts +106 -165
- package/core/src/nako_parser_async.mts +97 -0
- package/core/src/nako_parser_base.mts +4 -55
- package/core/src/nako_parser_message.mts +105 -0
- package/core/src/nako_parser_operator.mts +93 -0
- package/core/src/nako_plugin_manager.mts +260 -0
- package/core/src/nako_require.mts +292 -0
- package/core/src/nako_runner.mts +191 -0
- package/core/src/nako_tokenizer.mts +221 -0
- package/core/src/plugin_csv.mts +1 -1
- package/core/src/plugin_system.mts +34 -3259
- package/core/src/plugin_system_array.mts +699 -0
- package/core/src/plugin_system_datetime.mts +368 -0
- package/core/src/plugin_system_debug.mts +403 -0
- package/core/src/plugin_system_dict.mts +85 -0
- package/core/src/plugin_system_json.mts +73 -0
- package/core/src/plugin_system_math.mts +383 -0
- package/core/src/plugin_system_regexp.mts +120 -0
- package/core/src/plugin_system_stdio.mts +86 -0
- package/core/src/plugin_system_string.mts +666 -0
- package/core/src/plugin_system_timer.mts +152 -0
- package/core/src/plugin_system_types.mts +151 -0
- package/core/src/plugin_system_url.mts +193 -0
- package/core/src/plugin_toml.mts +3 -3
- package/core/test/fixtures/README.md +39 -0
- package/core/test/fixtures/make_parser_ast_golden.mjs +31 -0
- package/core/test/fixtures/parser_ast_golden.json +8027 -0
- package/core/test/fixtures/parser_corpus.mjs +120 -0
- package/core/test/indent_test.mjs +6 -0
- package/core/test/nako_basic_plugins_test.mjs +44 -0
- package/core/test/nako_event_test.mjs +85 -0
- package/core/test/nako_gen_perf_test.mjs +178 -0
- package/core/test/nako_parser_async_test.mjs +112 -0
- package/core/test/nako_parser_test.mjs +160 -0
- package/core/test/nako_plugin_manager_test.mjs +185 -0
- package/core/test/nako_require_test.mjs +153 -0
- package/core/test/nako_runner_test.mjs +114 -0
- package/core/test/nako_tokenizer_test.mjs +115 -0
- package/core/test/plugin_system_debug_test.mjs +141 -0
- package/core/test/plugin_system_split_test.mjs +179 -0
- package/core/test/plugin_system_test.mjs +6 -0
- package/core/tsconfig.json +0 -1
- package/package.json +17 -21
- package/release/_hash.txt +36 -36
- package/release/_script-tags.txt +16 -16
- package/release/command.json +1 -1
- package/release/command.json.js +1 -1
- package/release/command_cnako3.json +1 -1
- package/release/command_list.json +1 -1
- package/release/edit_main.js +6 -6
- package/release/edit_main.js.map +3 -3
- package/release/editor.js +6 -6
- package/release/plugin_keigo.js.map +3 -3
- package/release/plugin_markup.js +46 -46
- package/release/plugin_markup.js.map +3 -3
- package/release/plugin_weykturtle3d.js +1 -1
- package/release/plugin_weykturtle3d.js.map +3 -3
- package/release/version.js +2 -2
- package/release/version_main.js +2 -2
- package/release/version_main.js.map +1 -1
- package/release/wnako3.js +186 -213
- package/release/wnako3.js.map +4 -4
- package/release/wnako3webworker.js +172 -199
- package/release/wnako3webworker.js.map +4 -4
- package/src/cnako3mod.mjs +7 -2
- package/src/cnako3mod.mts +7 -2
- package/src/nako_version.mjs +2 -2
- package/src/nako_version.mts +2 -2
- package/src/plugin_browser_ajax.mjs +4 -4
- package/src/plugin_browser_ajax.mts +4 -4
- package/src/plugin_browser_audio.mjs +10 -10
- package/src/plugin_browser_audio.mts +10 -10
- package/src/plugin_browser_camera.mjs +4 -4
- package/src/plugin_browser_camera.mts +4 -4
- package/src/plugin_browser_canvas.mjs +2 -2
- package/src/plugin_browser_canvas.mts +2 -2
- package/src/plugin_browser_crypto.mjs +3 -3
- package/src/plugin_browser_crypto.mts +3 -3
- package/src/plugin_browser_dom_event.mjs +1 -1
- package/src/plugin_browser_dom_event.mts +1 -1
- package/src/plugin_browser_geolocation.mjs +1 -1
- package/src/plugin_browser_geolocation.mts +1 -1
- package/src/plugin_browser_hotkey.mjs +1 -1
- package/src/plugin_browser_hotkey.mts +1 -1
- package/src/plugin_browser_html.mjs +1 -1
- package/src/plugin_browser_html.mts +1 -1
- package/src/plugin_browser_location.mjs +1 -1
- package/src/plugin_browser_location.mts +1 -1
- package/src/plugin_browser_speech.mjs +1 -1
- package/src/plugin_browser_speech.mts +1 -1
- package/src/plugin_browser_storage.mjs +2 -2
- package/src/plugin_browser_storage.mts +2 -2
- package/src/plugin_httpserver.mjs +3 -3
- package/src/plugin_httpserver.mts +3 -3
- package/src/plugin_keigo.mjs +2 -2
- package/src/plugin_keigo.mts +2 -2
- package/src/plugin_node.mjs +48 -48
- package/src/plugin_node.mts +53 -53
- package/src/plugin_weykturtle3d.mjs +56 -56
- package/src/plugin_weykturtle3d.mts +56 -56
- package/src/wnako3.mjs +1 -1
- package/src/wnako3.mts +1 -1
- package/src/wnako3_editor.mjs +5 -5
- package/src/wnako3_editor.mts +5 -5
- package/src/wnako3mod.mjs +2 -2
- package/src/wnako3mod.mts +2 -2
- package/core/src/nako3.mjs +0 -1021
- package/core/src/nako_ast.mjs +0 -4
- package/core/src/nako_colors.mjs +0 -77
- package/core/src/nako_core_version.mjs +0 -8
- package/core/src/nako_csv.mjs +0 -193
- package/core/src/nako_errors.mjs +0 -166
- package/core/src/nako_from_dncl.mjs +0 -285
- package/core/src/nako_from_dncl2.mjs +0 -347
- package/core/src/nako_gen.mjs +0 -2500
- package/core/src/nako_global.mjs +0 -138
- package/core/src/nako_indent.mjs +0 -442
- package/core/src/nako_indent_chars.mjs +0 -29
- package/core/src/nako_indent_inline.mjs +0 -361
- package/core/src/nako_josi_list.mjs +0 -47
- package/core/src/nako_lex_rules.mjs +0 -319
- package/core/src/nako_lexer.mjs +0 -794
- package/core/src/nako_logger.mjs +0 -221
- package/core/src/nako_parser3.mjs +0 -3250
- package/core/src/nako_parser_base.mjs +0 -403
- package/core/src/nako_parser_const.mjs +0 -37
- package/core/src/nako_prepare.mjs +0 -329
- package/core/src/nako_reserved_words.mjs +0 -42
- package/core/src/nako_source_mapping.mjs +0 -207
- package/core/src/nako_test.mjs +0 -37
- package/core/src/nako_token.mjs +0 -1
- package/core/src/nako_tools.mjs +0 -53
- package/core/src/nako_types.mjs +0 -14
- package/core/src/plugin_api.mjs +0 -4
- package/core/src/plugin_csv.mjs +0 -97
- package/core/src/plugin_math.mjs +0 -352
- package/core/src/plugin_promise.mjs +0 -102
- package/core/src/plugin_system.mjs +0 -3810
- package/core/src/plugin_test.mjs +0 -52
- package/core/src/plugin_toml.mjs +0 -39
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview なでしこ3 plugin_system の分割ファイル
|
|
3
|
+
*
|
|
4
|
+
* タイマー処理の命令を定義する。
|
|
5
|
+
* このファイルは単独のプラグインではなく、plugin_system.mts へマージされる。(#2351)
|
|
6
|
+
*/
|
|
7
|
+
import { NakoRuntimeError } from './nako_errors.mjs'
|
|
8
|
+
import { NakoSystem } from './plugin_api.mjs'
|
|
9
|
+
|
|
10
|
+
export default {
|
|
11
|
+
// @タイマー
|
|
12
|
+
'秒待': { // @ N秒の間待機する // @びょうまつ
|
|
13
|
+
type: 'func',
|
|
14
|
+
josi: [['']],
|
|
15
|
+
pure: true,
|
|
16
|
+
asyncFn: true,
|
|
17
|
+
fn: function(n: any, sys:any): Promise<void> {
|
|
18
|
+
return new Promise((resolve, reject) => {
|
|
19
|
+
try {
|
|
20
|
+
// タイマーを仕掛ける
|
|
21
|
+
const timerId = setTimeout(() => {
|
|
22
|
+
// タイマー使用中リストに追加したIDを削除
|
|
23
|
+
const i = sys.__timeout.indexOf(timerId)
|
|
24
|
+
if (i >= 0) { sys.__timeout.splice(i, 1) }
|
|
25
|
+
// Promiseを終了
|
|
26
|
+
resolve()
|
|
27
|
+
}, parseFloat(n) * 1000)
|
|
28
|
+
// タイマー使用中リストに追加
|
|
29
|
+
sys.__timeout.push(timerId)
|
|
30
|
+
} catch (err: any) {
|
|
31
|
+
reject(err)
|
|
32
|
+
}
|
|
33
|
+
})
|
|
34
|
+
},
|
|
35
|
+
return_none: true
|
|
36
|
+
},
|
|
37
|
+
'秒待機': { // @ N秒の間待機する(『秒待』と同じ) // @びょうたいき
|
|
38
|
+
type: 'func',
|
|
39
|
+
josi: [['']],
|
|
40
|
+
pure: true,
|
|
41
|
+
asyncFn: true,
|
|
42
|
+
fn: async function(n: any, sys: any) {
|
|
43
|
+
const p = sys.__exec('秒待', [n, sys])
|
|
44
|
+
return await p
|
|
45
|
+
},
|
|
46
|
+
return_none: true
|
|
47
|
+
},
|
|
48
|
+
'秒逐次待機': { // @ (非推奨) 逐次実行構文にて、N秒の間待機する (廃止予定) // @びょうちくじたいき
|
|
49
|
+
type: 'func',
|
|
50
|
+
josi: [['']],
|
|
51
|
+
pure: true,
|
|
52
|
+
asyncFn: true,
|
|
53
|
+
fn: async function(n: any, sys: any) {
|
|
54
|
+
const p = sys.__exec('秒待', [n, sys])
|
|
55
|
+
return await p
|
|
56
|
+
},
|
|
57
|
+
return_none: true
|
|
58
|
+
},
|
|
59
|
+
'秒後': { // @無名関数(あるいは、文字列で関数名を指定)FをN秒後に実行する。変数『対象』にタイマーIDを代入する。 // @びょうご
|
|
60
|
+
type: 'func',
|
|
61
|
+
josi: [['を'], ['']],
|
|
62
|
+
pure: true,
|
|
63
|
+
fn: function(f: any, n: any, sys: any) {
|
|
64
|
+
// 文字列で指定された関数をオブジェクトに変換
|
|
65
|
+
if (typeof f === 'string') { f = sys.__findFunc(f, '秒後') }
|
|
66
|
+
// 1回限りのタイマーをセット
|
|
67
|
+
const timerId = setTimeout(() => {
|
|
68
|
+
// 使用中リストに追加したIDを削除
|
|
69
|
+
const i = sys.__timeout.indexOf(timerId)
|
|
70
|
+
if (i >= 0) { sys.__timeout.splice(i, 1) }
|
|
71
|
+
try {
|
|
72
|
+
f(timerId, sys)
|
|
73
|
+
} catch (e: any) {
|
|
74
|
+
let err = e
|
|
75
|
+
if (!(e instanceof NakoRuntimeError)) {
|
|
76
|
+
err = new NakoRuntimeError(e, sys.__getSysVar('__line'))
|
|
77
|
+
}
|
|
78
|
+
sys.logger.error(err)
|
|
79
|
+
}
|
|
80
|
+
}, parseFloat(n) * 1000)
|
|
81
|
+
sys.__timeout.unshift(timerId)
|
|
82
|
+
sys.__setSysVar('対象', timerId)
|
|
83
|
+
return timerId
|
|
84
|
+
}
|
|
85
|
+
},
|
|
86
|
+
'秒毎': { // @無名関数(あるいは、文字列で関数名を指定)FをN秒ごとに実行する(『タイマー停止』で停止できる)。変数『対象』にタイマーIDを代入する。 // @びょうごと
|
|
87
|
+
type: 'func',
|
|
88
|
+
josi: [['を'], ['']],
|
|
89
|
+
pure: false,
|
|
90
|
+
fn: function(f: any, n: any, sys: any) {
|
|
91
|
+
// 文字列で指定された関数をオブジェクトに変換
|
|
92
|
+
if (typeof f === 'string') { f = sys.__findFunc(f, '秒毎') }
|
|
93
|
+
// タイマーをセット
|
|
94
|
+
const timerId = setInterval(() => {
|
|
95
|
+
f(timerId, sys)
|
|
96
|
+
}, parseFloat(n) * 1000)
|
|
97
|
+
// タイマーIDを追加
|
|
98
|
+
sys.__interval.unshift(timerId)
|
|
99
|
+
sys.__setSysVar('対象', timerId)
|
|
100
|
+
return timerId
|
|
101
|
+
}
|
|
102
|
+
},
|
|
103
|
+
'秒タイマー開始時': { // @無名関数(あるいは、文字列で関数名を指定)FをN秒ごとに実行する(『秒毎』と同じ) // @びょうたいまーかいししたとき
|
|
104
|
+
type: 'func',
|
|
105
|
+
josi: [['を'], ['']],
|
|
106
|
+
pure: false,
|
|
107
|
+
fn: function(f: any, n: any, sys: any) {
|
|
108
|
+
return sys.__exec('秒毎', [f, n, sys])
|
|
109
|
+
}
|
|
110
|
+
},
|
|
111
|
+
'タイマー停止': { // @『秒毎』『秒後』や『秒タイマー開始』で開始したタイマーを停止する // @たいまーていし
|
|
112
|
+
type: 'func',
|
|
113
|
+
josi: [['の', 'で']],
|
|
114
|
+
pure: true,
|
|
115
|
+
fn: function(timerId: any, sys: any) {
|
|
116
|
+
const i = sys.__interval.indexOf(timerId)
|
|
117
|
+
if (i >= 0) {
|
|
118
|
+
sys.__interval.splice(i, 1)
|
|
119
|
+
clearInterval(timerId)
|
|
120
|
+
return true
|
|
121
|
+
}
|
|
122
|
+
const j = sys.__timeout.indexOf(timerId)
|
|
123
|
+
if (j >= 0) {
|
|
124
|
+
sys.__timeout.splice(j, 1)
|
|
125
|
+
clearTimeout(timerId)
|
|
126
|
+
return true
|
|
127
|
+
}
|
|
128
|
+
return false
|
|
129
|
+
},
|
|
130
|
+
return_none: false
|
|
131
|
+
},
|
|
132
|
+
'全タイマー停止': { // @『秒毎』『秒後』や『秒タイマー開始』で開始したタイマーを全部停止する // @ぜんたいまーていし
|
|
133
|
+
type: 'func',
|
|
134
|
+
josi: [],
|
|
135
|
+
pure: true,
|
|
136
|
+
fn: function(sys: NakoSystem) {
|
|
137
|
+
// clearInterval
|
|
138
|
+
for (let i = 0; i < sys.__interval.length; i++) {
|
|
139
|
+
const timerId = sys.__interval[i]
|
|
140
|
+
clearInterval(timerId)
|
|
141
|
+
}
|
|
142
|
+
sys.__interval = []
|
|
143
|
+
// clearTimeout
|
|
144
|
+
for (let i = 0; i < sys.__timeout.length; i++) {
|
|
145
|
+
const timerId = sys.__timeout[i]
|
|
146
|
+
clearTimeout(timerId)
|
|
147
|
+
}
|
|
148
|
+
sys.__timeout = []
|
|
149
|
+
},
|
|
150
|
+
return_none: true
|
|
151
|
+
},
|
|
152
|
+
}
|
|
@@ -0,0 +1,151 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview なでしこ3 plugin_system の分割ファイル
|
|
3
|
+
*
|
|
4
|
+
* 型変換の命令を定義する。
|
|
5
|
+
* このファイルは単独のプラグインではなく、plugin_system.mts へマージされる。(#2351)
|
|
6
|
+
*/
|
|
7
|
+
export default {
|
|
8
|
+
// @型変換
|
|
9
|
+
'変数型確認': { // @変数Vの型を返す // @へんすうかたかくにん
|
|
10
|
+
type: 'func',
|
|
11
|
+
josi: [['の']],
|
|
12
|
+
pure: true,
|
|
13
|
+
fn: function(v: any) {
|
|
14
|
+
return (typeof v)
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
'TYPEOF': { // @変数Vの型を返す // @TYPEOF
|
|
18
|
+
type: 'func',
|
|
19
|
+
josi: [['の']],
|
|
20
|
+
pure: true,
|
|
21
|
+
fn: function(v: any) {
|
|
22
|
+
return (typeof v)
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
'文字列変換': { // @値Vを文字列に変換 // @もじれつへんかん
|
|
26
|
+
type: 'func',
|
|
27
|
+
josi: [['を']],
|
|
28
|
+
pure: true,
|
|
29
|
+
fn: function(v: any): string {
|
|
30
|
+
return String(v)
|
|
31
|
+
}
|
|
32
|
+
},
|
|
33
|
+
'TOSTR': { // @値Vを文字列に変換 // @TOSTR
|
|
34
|
+
type: 'func',
|
|
35
|
+
josi: [['を']],
|
|
36
|
+
pure: true,
|
|
37
|
+
fn: function(v: any): string {
|
|
38
|
+
return String(v)
|
|
39
|
+
}
|
|
40
|
+
},
|
|
41
|
+
'整数変換': { // @値Vを整数に変換 // @せいすうへんかん
|
|
42
|
+
type: 'func',
|
|
43
|
+
josi: [['を']],
|
|
44
|
+
pure: true,
|
|
45
|
+
fn: function(v: any): number {
|
|
46
|
+
return parseInt(v)
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
'TOINT': { // @値Vを整数に変換 // @TOINT
|
|
50
|
+
type: 'func',
|
|
51
|
+
josi: [['を']],
|
|
52
|
+
pure: true,
|
|
53
|
+
fn: function(v: any): number {
|
|
54
|
+
return parseInt(v)
|
|
55
|
+
}
|
|
56
|
+
},
|
|
57
|
+
'実数変換': { // @値Vを実数に変換 // @じっすうへんかん
|
|
58
|
+
type: 'func',
|
|
59
|
+
josi: [['を']],
|
|
60
|
+
pure: true,
|
|
61
|
+
fn: function(v: any): number {
|
|
62
|
+
return parseFloat(v)
|
|
63
|
+
}
|
|
64
|
+
},
|
|
65
|
+
'TOFLOAT': { // @値Vを実数に変換 // @TOFLOAT
|
|
66
|
+
type: 'func',
|
|
67
|
+
josi: [['を']],
|
|
68
|
+
pure: true,
|
|
69
|
+
fn: function(v: any): number {
|
|
70
|
+
return parseFloat(v)
|
|
71
|
+
}
|
|
72
|
+
},
|
|
73
|
+
'INT': { // @値Vを整数に変換 // @INT
|
|
74
|
+
type: 'func',
|
|
75
|
+
josi: [['の']],
|
|
76
|
+
pure: true,
|
|
77
|
+
fn: function(v: any): number {
|
|
78
|
+
return parseInt(v)
|
|
79
|
+
}
|
|
80
|
+
},
|
|
81
|
+
'FLOAT': { // @値Vを実数に変換 // @FLOAT
|
|
82
|
+
type: 'func',
|
|
83
|
+
josi: [['の']],
|
|
84
|
+
pure: true,
|
|
85
|
+
fn: function(v: any): number {
|
|
86
|
+
return parseFloat(v)
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
'NAN判定': { // @値VがNaNかどうかを判定(命令『非数判定』を使う事を推奨) // @NANはんてい
|
|
90
|
+
type: 'func',
|
|
91
|
+
josi: [['を']],
|
|
92
|
+
pure: true,
|
|
93
|
+
fn: function(v: any): boolean {
|
|
94
|
+
return isNaN(v)
|
|
95
|
+
}
|
|
96
|
+
},
|
|
97
|
+
'非数判定': { // @値Vが非数かどうかを判定(NAN判定より堅牢) // @ひすうはんてい
|
|
98
|
+
type: 'func',
|
|
99
|
+
josi: [['を']],
|
|
100
|
+
pure: true,
|
|
101
|
+
fn: function(v: any): boolean {
|
|
102
|
+
// https://developer.mozilla.org/ja/docs/Web/JavaScript/Reference/Global_Objects/Number/isNaN
|
|
103
|
+
return Number.isNaN(v)
|
|
104
|
+
}
|
|
105
|
+
},
|
|
106
|
+
'HEX': { // @値Vを16進数に変換 // @HEX
|
|
107
|
+
type: 'func',
|
|
108
|
+
josi: [['の']],
|
|
109
|
+
pure: true,
|
|
110
|
+
fn: function(a: any): string {
|
|
111
|
+
return parseInt(a).toString(16)
|
|
112
|
+
}
|
|
113
|
+
},
|
|
114
|
+
'進数変換': { // @値VをN進数に変換 // @しんすうへんかん
|
|
115
|
+
type: 'func',
|
|
116
|
+
josi: [['を', 'の'], ['']],
|
|
117
|
+
pure: true,
|
|
118
|
+
fn: function(v: any, n: number): string {
|
|
119
|
+
return parseInt(v).toString(n)
|
|
120
|
+
}
|
|
121
|
+
},
|
|
122
|
+
'二進': { // @値Vを2進数に変換 // @にしん
|
|
123
|
+
type: 'func',
|
|
124
|
+
josi: [['を', 'の', 'から']],
|
|
125
|
+
pure: true,
|
|
126
|
+
fn: function(v: any): string {
|
|
127
|
+
return parseInt(v).toString(2)
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
'二進表示': { // @値Vを2進数に変換して表示 // @にしんひょうじ
|
|
131
|
+
type: 'func',
|
|
132
|
+
josi: [['を', 'の', 'から']],
|
|
133
|
+
pure: true,
|
|
134
|
+
fn: function(v: any, sys: any) {
|
|
135
|
+
const s = parseInt(v).toString(2)
|
|
136
|
+
sys.__exec('表示', [s, sys])
|
|
137
|
+
}
|
|
138
|
+
},
|
|
139
|
+
'RGB': { // @HTML用のカラーコードを返すRGB(R,G,B)で各値は0-255 // @RGB
|
|
140
|
+
type: 'func',
|
|
141
|
+
josi: [['と'], ['の'], ['で']],
|
|
142
|
+
pure: true,
|
|
143
|
+
fn: function(r: any, g: any, b: any): string {
|
|
144
|
+
const z2 = (v: any): string => {
|
|
145
|
+
const v2: string = '00' + (parseInt(String(v)).toString(16))
|
|
146
|
+
return v2.substring(v2.length - 2, v2.length)
|
|
147
|
+
}
|
|
148
|
+
return '#' + z2(r) + z2(g) + z2(b)
|
|
149
|
+
}
|
|
150
|
+
},
|
|
151
|
+
}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileOverview なでしこ3 plugin_system の分割ファイル
|
|
3
|
+
*
|
|
4
|
+
* URLエンコード・パラメータ処理・BASE64・パス操作の命令を定義する。
|
|
5
|
+
* このファイルは単独のプラグインではなく、plugin_system.mts へマージされる。(#2351)
|
|
6
|
+
*/
|
|
7
|
+
import { NakoSystem } from './plugin_api.mjs'
|
|
8
|
+
|
|
9
|
+
export default {
|
|
10
|
+
// @URLエンコードとパラメータ
|
|
11
|
+
'URLエンコード': { // @URLエンコードして返す // @URLえんこーど
|
|
12
|
+
type: 'func',
|
|
13
|
+
josi: [['を', 'から']],
|
|
14
|
+
pure: true,
|
|
15
|
+
fn: function(text: any) {
|
|
16
|
+
return encodeURIComponent(text)
|
|
17
|
+
}
|
|
18
|
+
},
|
|
19
|
+
'URLデコード': { // @URLデコードして返す // @URLでこーど
|
|
20
|
+
type: 'func',
|
|
21
|
+
josi: [['を', 'へ', 'に']],
|
|
22
|
+
pure: true,
|
|
23
|
+
fn: function(text: any) {
|
|
24
|
+
return decodeURIComponent(text)
|
|
25
|
+
}
|
|
26
|
+
},
|
|
27
|
+
'URLパラメータ解析': { // @URLパラメータを解析してハッシュで返す // @URLぱらめーたかいせき
|
|
28
|
+
type: 'func',
|
|
29
|
+
josi: [['を', 'の', 'から']],
|
|
30
|
+
pure: true,
|
|
31
|
+
fn: function(url: string, sys: any) {
|
|
32
|
+
const res: any = {}
|
|
33
|
+
if (typeof url !== 'string') {
|
|
34
|
+
return res
|
|
35
|
+
}
|
|
36
|
+
const p = url.split('?')
|
|
37
|
+
if (p.length <= 1) {
|
|
38
|
+
return res
|
|
39
|
+
}
|
|
40
|
+
const params = p[1].split('&')
|
|
41
|
+
for (const line of params) {
|
|
42
|
+
if (line === '') { continue }
|
|
43
|
+
const eqIdx = line.indexOf('=')
|
|
44
|
+
let k: string
|
|
45
|
+
let v: string
|
|
46
|
+
if (eqIdx < 0) {
|
|
47
|
+
k = line
|
|
48
|
+
v = ''
|
|
49
|
+
} else {
|
|
50
|
+
k = line.substring(0, eqIdx)
|
|
51
|
+
v = line.substring(eqIdx + 1)
|
|
52
|
+
}
|
|
53
|
+
const decodedKey = sys.__exec('URLデコード', [k])
|
|
54
|
+
const decodedVal = sys.__exec('URLデコード', [v])
|
|
55
|
+
res[decodedKey] = decodedVal
|
|
56
|
+
}
|
|
57
|
+
return res
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
|
|
61
|
+
// @BASE64
|
|
62
|
+
'BASE64エンコード': { // @BASE64エンコードして返す // @BASE64えんこーど
|
|
63
|
+
type: 'func',
|
|
64
|
+
josi: [['を', 'から']],
|
|
65
|
+
pure: true,
|
|
66
|
+
fn: function(text: any) {
|
|
67
|
+
// browser?
|
|
68
|
+
if (typeof (window) !== 'undefined' && (window as any).btoa) {
|
|
69
|
+
const u8a: any = new TextEncoder().encode(text)
|
|
70
|
+
const utf8str = String.fromCharCode.apply(null, u8a)
|
|
71
|
+
return btoa(utf8str)
|
|
72
|
+
}
|
|
73
|
+
// Node?
|
|
74
|
+
if (typeof (Buffer) !== 'undefined') {
|
|
75
|
+
return Buffer.from(text).toString('base64')
|
|
76
|
+
}
|
|
77
|
+
throw new Error('『BASE64エンコード』は利用できません。')
|
|
78
|
+
}
|
|
79
|
+
},
|
|
80
|
+
'BASE64デコード': { // @BASE64デコードして返す // @BASE64でこーど
|
|
81
|
+
type: 'func',
|
|
82
|
+
josi: [['を', 'へ', 'に']],
|
|
83
|
+
pure: true,
|
|
84
|
+
fn: function(text: any) {
|
|
85
|
+
if (typeof (window) !== 'undefined' && (window as any).atob) {
|
|
86
|
+
const decodedUtf8str = atob(text)
|
|
87
|
+
const dec: any = Array.prototype.map.call(decodedUtf8str, c => c.charCodeAt())
|
|
88
|
+
const decodedArray = new Uint8Array(dec)
|
|
89
|
+
return new TextDecoder('UTF-8').decode(decodedArray)
|
|
90
|
+
}
|
|
91
|
+
// Node?
|
|
92
|
+
if (typeof (Buffer) !== 'undefined') {
|
|
93
|
+
return Buffer.from(text, 'base64').toString()
|
|
94
|
+
}
|
|
95
|
+
throw new Error('『BASE64デコード』は利用できません。')
|
|
96
|
+
}
|
|
97
|
+
},
|
|
98
|
+
|
|
99
|
+
// @パス操作
|
|
100
|
+
'拡張子抽出': { // @ファイル名Sから拡張子を抽出する // @かくちょうしちゅうしゅつ
|
|
101
|
+
type: 'func',
|
|
102
|
+
josi: [['から', 'の']],
|
|
103
|
+
pure: true,
|
|
104
|
+
fn: function(fname: string, sys: NakoSystem) {
|
|
105
|
+
if (fname === null || fname === undefined) { return '' }
|
|
106
|
+
const sep = sys.pathSeparator || '/'
|
|
107
|
+
if (fname.indexOf(sep) >= 0) { // パス記号があればファイル名を抽出
|
|
108
|
+
const parts = fname.split(sep)
|
|
109
|
+
fname = parts[parts.length - 1]
|
|
110
|
+
}
|
|
111
|
+
const m = fname.match(/(\.[a-zA-Z0-9_\-+]+)$/)
|
|
112
|
+
if (m) { return m[1] }
|
|
113
|
+
return ''
|
|
114
|
+
}
|
|
115
|
+
},
|
|
116
|
+
'拡張子変更': { // @ファイル名Aの拡張子をBに変更して返す // @かくちょうしへんこう
|
|
117
|
+
type: 'func',
|
|
118
|
+
josi: [['の', 'を', 'から'], ['に', 'へ']],
|
|
119
|
+
pure: true,
|
|
120
|
+
fn: function(fname: string, ext: string, sys: NakoSystem) {
|
|
121
|
+
if (fname === null || fname === undefined) { return ext }
|
|
122
|
+
const sep = sys.pathSeparator || '/'
|
|
123
|
+
const pathList = fname.split(sep)
|
|
124
|
+
const filename = pathList[pathList.length - 1]
|
|
125
|
+
const pathStr = pathList.slice(0, -1).join(sep)
|
|
126
|
+
const rawExt = (ext ?? '').trim()
|
|
127
|
+
let extWithDot = rawExt
|
|
128
|
+
if (rawExt !== '' ) {
|
|
129
|
+
extWithDot = rawExt.startsWith('.') ? rawExt : '.' + rawExt
|
|
130
|
+
}
|
|
131
|
+
const newFilename = filename.replace(/(\.[a-zA-Z0-9_\-+]+)?$/, extWithDot)
|
|
132
|
+
return sys.__exec('終端パス追加', [pathStr, sys]) + newFilename
|
|
133
|
+
}
|
|
134
|
+
},
|
|
135
|
+
'終端パス追加': { // @パスSの終端にパス区切り文字を追加して返す // @しゅうたんぱすついか
|
|
136
|
+
type: 'func',
|
|
137
|
+
josi: [['に', 'へ']],
|
|
138
|
+
pure: true,
|
|
139
|
+
fn: function(path: string, sys: NakoSystem) {
|
|
140
|
+
const sep = sys.pathSeparator || '/'
|
|
141
|
+
if (path === undefined || path === null || path === '') {
|
|
142
|
+
return ''
|
|
143
|
+
}
|
|
144
|
+
if (path.endsWith(sep)) {
|
|
145
|
+
return path
|
|
146
|
+
}
|
|
147
|
+
return path + sep
|
|
148
|
+
}
|
|
149
|
+
},
|
|
150
|
+
'終端パス除去': { // @フォルダ名DIRの末尾にあるパス記号を削除する // @しゅうたんぱすじょきょ
|
|
151
|
+
type: 'func',
|
|
152
|
+
josi: [['の', 'から']],
|
|
153
|
+
pure: true,
|
|
154
|
+
fn: function(dir: string, sys: NakoSystem) {
|
|
155
|
+
const sep = sys.pathSeparator || '/'
|
|
156
|
+
if (!dir) { return '' }
|
|
157
|
+
if (dir.endsWith(sep)) {
|
|
158
|
+
return dir.substring(0, dir.length - 1)
|
|
159
|
+
} else {
|
|
160
|
+
return dir
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
},
|
|
164
|
+
'終端パス削除': { // @フォルダ名DIRの末尾にあるパス記号を削除する // @しゅうたんぱすさくじょ
|
|
165
|
+
type: 'func',
|
|
166
|
+
josi: [['の', 'から']],
|
|
167
|
+
pure: true,
|
|
168
|
+
fn: function(dir: string, sys: NakoSystem) {
|
|
169
|
+
return sys.__exec('終端パス除去', [dir, sys])
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
'ファイル名抽出': { // @パスPATHからファイル名を抽出して返す // @ふぁいるめいちゅうしゅつ
|
|
173
|
+
type: 'func',
|
|
174
|
+
josi: [['の', 'から']],
|
|
175
|
+
pure: true,
|
|
176
|
+
fn: function(dir: string, sys: NakoSystem) {
|
|
177
|
+
const sep = sys.pathSeparator || '/'
|
|
178
|
+
const parts = dir.split(sep)
|
|
179
|
+
return parts[parts.length - 1]
|
|
180
|
+
}
|
|
181
|
+
},
|
|
182
|
+
'パス抽出': { // @パスPATHからディレクトリ部分を抽出して返す // @ぱすちゅうしゅつ
|
|
183
|
+
type: 'func',
|
|
184
|
+
josi: [['の', 'から']],
|
|
185
|
+
pure: true,
|
|
186
|
+
fn: function(dir: string, sys: NakoSystem) {
|
|
187
|
+
const sep = sys.pathSeparator || '/'
|
|
188
|
+
const parts = dir.split(sep)
|
|
189
|
+
parts.pop()
|
|
190
|
+
return parts.join(sep)
|
|
191
|
+
}
|
|
192
|
+
}
|
|
193
|
+
}
|
package/core/src/plugin_toml.mts
CHANGED
|
@@ -16,7 +16,7 @@ const PluginTOML = {
|
|
|
16
16
|
type: 'func',
|
|
17
17
|
josi: [],
|
|
18
18
|
pure: true,
|
|
19
|
-
fn: function(
|
|
19
|
+
fn: function(_sys: any) {
|
|
20
20
|
}
|
|
21
21
|
},
|
|
22
22
|
// @TOML
|
|
@@ -24,7 +24,7 @@ const PluginTOML = {
|
|
|
24
24
|
type: 'func',
|
|
25
25
|
josi: [['を', 'の', 'から']],
|
|
26
26
|
pure: true,
|
|
27
|
-
fn: function(s: string,
|
|
27
|
+
fn: function(s: string, _sys: any) {
|
|
28
28
|
return TOML.parse(s)
|
|
29
29
|
}
|
|
30
30
|
},
|
|
@@ -32,7 +32,7 @@ const PluginTOML = {
|
|
|
32
32
|
type: 'func',
|
|
33
33
|
josi: [['を', 'から', 'の']],
|
|
34
34
|
pure: true,
|
|
35
|
-
fn: function(s: any,
|
|
35
|
+
fn: function(s: any, _sys: any) {
|
|
36
36
|
return TOML.stringify(s)
|
|
37
37
|
}
|
|
38
38
|
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
# core/test/fixtures
|
|
2
|
+
|
|
3
|
+
テストが読み込む固定データを置くディレクトリです。
|
|
4
|
+
`npm run test:core` のテストグロブは `core/test/*.mjs` なので、
|
|
5
|
+
このディレクトリのファイルがテストとして実行されることはありません。
|
|
6
|
+
|
|
7
|
+
## 構文解析器のゴールデン AST (#2364)
|
|
8
|
+
|
|
9
|
+
| ファイル | 役割 |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `parser_corpus.mjs` | 構文解析のコーパス(なでしこコード集)と、AST をプレーン化するヘルパー |
|
|
12
|
+
| `parser_ast_golden.json` | コーパスを構文解析した結果の AST を固定したもの |
|
|
13
|
+
| `make_parser_ast_golden.mjs` | `parser_ast_golden.json` を生成するスクリプト |
|
|
14
|
+
|
|
15
|
+
`core/test/nako_parser_test.mjs` が、現在の構文解析結果と
|
|
16
|
+
`parser_ast_golden.json` を `assert.deepStrictEqual` で比較します。
|
|
17
|
+
AST の全キー・全値に加えて**キーの並び順**まで比較するため、
|
|
18
|
+
構文解析器に手を入れて結果が少しでも変われば必ず検出できます。
|
|
19
|
+
|
|
20
|
+
### ゴールデンを再生成する
|
|
21
|
+
|
|
22
|
+
コーパス(`parser_corpus.mjs` の `PARSER_CORPUS`)を追加・変更したときや、
|
|
23
|
+
**意図的に**構文解析の結果を変更したときに再生成します。
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
npm run build:tsc && node core/test/fixtures/make_parser_ast_golden.mjs
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
`core/src/*.mjs` はビルド生成物(git 管理外)なので、
|
|
30
|
+
**再生成の前に必ずビルドしてください**。ビルドを忘れると古いコードの
|
|
31
|
+
AST がゴールデンになってしまいます。
|
|
32
|
+
|
|
33
|
+
### 差分が出たときの読み方
|
|
34
|
+
|
|
35
|
+
構文解析器のリファクタリング中にこのテストが落ちた場合、それは
|
|
36
|
+
**リファクタリングで挙動が変わってしまった**ことを意味します。
|
|
37
|
+
ゴールデンを再生成して通す前に、差分が意図したものか必ず確認してください。
|
|
38
|
+
`assert.deepStrictEqual` は差分箇所を表示するので、
|
|
39
|
+
どのノードのどのキーが変わったかを追えます。
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/* eslint-disable no-undef */
|
|
2
|
+
/**
|
|
3
|
+
* `parser_ast_golden.json` を生成するスクリプト (#2364)
|
|
4
|
+
*
|
|
5
|
+
* コーパス(`parser_corpus.mjs` の PARSER_CORPUS)を構文解析し、
|
|
6
|
+
* その AST をゴールデンファイルとして書き出す。
|
|
7
|
+
*
|
|
8
|
+
* 実行前に必ずビルドすること(core/src/*.mjs はビルド生成物のため)。
|
|
9
|
+
*
|
|
10
|
+
* npm run build:tsc
|
|
11
|
+
* node core/test/fixtures/make_parser_ast_golden.mjs
|
|
12
|
+
*
|
|
13
|
+
* このディレクトリは `core/test/*.mjs` のテストグロブに含まれないので、
|
|
14
|
+
* テスト実行時にこのファイルが走ることはない。
|
|
15
|
+
*/
|
|
16
|
+
import fs from 'node:fs'
|
|
17
|
+
import { PARSER_CORPUS, parseToPlainAst } from './parser_corpus.mjs'
|
|
18
|
+
|
|
19
|
+
const golden = {}
|
|
20
|
+
for (const [name, code] of Object.entries(PARSER_CORPUS)) {
|
|
21
|
+
try {
|
|
22
|
+
golden[name] = parseToPlainAst(code)
|
|
23
|
+
} catch (err) {
|
|
24
|
+
console.error(`構文解析に失敗しました: ${name}`)
|
|
25
|
+
throw err
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
const outPath = new URL('./parser_ast_golden.json', import.meta.url)
|
|
30
|
+
fs.writeFileSync(outPath, JSON.stringify(golden, null, 1) + '\n', 'utf8')
|
|
31
|
+
console.log(`${Object.keys(golden).length} 件のゴールデン AST を書き出しました`)
|