diff --git a/core/src/nako_gen.mts b/core/src/nako_gen.mts index d52e3e24..605de48c 100644 --- a/core/src/nako_gen.mts +++ b/core/src/nako_gen.mts @@ -339,6 +339,8 @@ export class NakoGen { // 定数を埋め込む code += '__self.constPools = ' + JSON.stringify(this.constPools) + ';\n' code += '__self.constPoolsTemplate = ' + JSON.stringify(this.constPoolsTemplate) + ';\n' + // + code += '__self.__propAccessor = [];\n' // なでしこの関数定義を行う let nakoFuncCode = '' this.nakoFuncList.forEach((value, key) => { @@ -1855,8 +1857,10 @@ export class NakoGen { } } // プロパティへの代入式を作る - code += `if (typeof ${nameJs}.__setProp === 'function') { ${nameJs}.__setProp('${propTop}', ${value}, __self); } ` - code += `else { ${nameJs}['${propTop}'] = ${value} };` + code += `if (typeof ${nameJs}.__setProp === 'function') { ${nameJs}.__setProp('${propTop}', ${value}, __self); } else {` + code += `__self.__checkPropAccessor('set', ${nameJs});` + code += `if (typeof ${nameJs}.__setProp === 'function') { ${nameJs}.__setProp('${propTop}', ${value}, __self); } else {` + code += `${nameJs}['${propTop}'] = ${value} }};` return ';' + this.convLineno(node, false) + code + '\n' } // プロパティへの参照 (#1793) @@ -1872,7 +1876,10 @@ export class NakoGen { const propKey = propList[0].value const code_call = `${name}.__getProp('${propKey}', __self)` const code_prop = `${name}['${propKey}']` - const code_if = `if (${name}.__getProp) { return ${code_call} } else { return ${code_prop} }` + const code_checkAccessor = `__self.__checkPropAccessor('get', ${name});\n` + + `if (typeof ${name}.__getProp === 'function') { return ${code_call} }\n` + + `return ${code_prop}\n` + const code_if = `if (${name}.__getProp) { return ${code_call} } else { ${code_checkAccessor} }` code = `( (()=>{ ${code_if} })() )` } else { const arrs = [] @@ -1886,7 +1893,10 @@ export class NakoGen { const arrStr = '[' + arrs.join(',') + ']' const code_call = `${name}.__getProp(${arrStr}, __self)` const code_prop = `${name}${keyStr}` - const code_if = `if (${name}.__getProp) { return ${code_call} } else { return ${code_prop} }` + const code_checkAccessor = `__self.__checkPropAccessor('get', ${name});\n` + + `if (${name}.__getProp) { return ${code_call} }\n` + + `return ${code_prop}\n` + const code_if = `if (${name}.__getProp) { return ${code_call} } else { ${code_checkAccessor} }` code = `( (()=>{ ${code_if} })() )` } return code @@ -2027,6 +2037,7 @@ self.__varslist = [self.newVariables(), self.newVariables(), self.newVariables() self.__v0 = self.__varslist[0] self.initFuncList = [] self.clearFuncList = [] +self.__propAccessor = [] // --- jsInit --- __jsInit__ // --- Copy module functions --- diff --git a/core/src/plugin_api.mts b/core/src/plugin_api.mts index 050bd0aa..cdd75996 100644 --- a/core/src/plugin_api.mts +++ b/core/src/plugin_api.mts @@ -37,6 +37,8 @@ export interface NakoSystem { __parseFloatOrBigint(v: NakoValue): number | bigint; __evalJS(code: string, sys?: NakoSystem): NakoValue; __evalSafe(code: string): NakoValue; + __registPropAccessor(f: Function, getProp: (prop: string|string[], sys: NakoSystem) => any, setProp: (prop: string|string[], value: object, sys: NakoSystem) => any):void; + __checkPropAccessor(mode: 'get'|'set', obj: any):void; josiList: string[]; reservedWords: string[]; // 実際には存在するが利用が非推奨なメソッドやプロパティ diff --git a/core/src/plugin_system.mts b/core/src/plugin_system.mts index 5d747312..6de93855 100644 --- a/core/src/plugin_system.mts +++ b/core/src/plugin_system.mts @@ -177,6 +177,34 @@ export default { return null } } + // Propアクセス支援 + sys.__registPropAccessor = (f: Function, getProp: (prop: string|string[], sys: NakoSystem) => any, setProp: (prop: string|string[], value: object, sys: NakoSystem) => any, sys?: NakoSystem) => { + system.__propAccessor.push( + { + target: f, + getProp, + setProp + } + ) + } + sys.__checkPropAccessor = (mode: 'get'|'set', obj: any):void => { + if ((mode === 'get' && obj.__getProp === undefined) || (mode === 'set' && obj.__setProp === undefined)) { + for (let i = 0; i < system.__propAccessor.length; i++) { + const accs = system.__propAccessor[i] + if (accs.target[Symbol.hasInstance](obj)) { + if (accs.getProp) { + obj.__getProp = accs.getProp + } else { obj.__getProp = null } + if (accs.setProp) { + obj.__setProp = accs.setProp + } else { obj.__setProp = null } + return + } + } + obj.__getProp = obj.__setProp = null + } + } + } }, '!クリア': { diff --git a/src/plugin_browser.mts b/src/plugin_browser.mts index 2f26b999..00e476c9 100644 --- a/src/plugin_browser.mts +++ b/src/plugin_browser.mts @@ -1,7 +1,7 @@ /** * @fileOverview ブラウザプラグイン */ -import { NakoValue, NakoCallback, NakoCallbackEvent } from '../core/src/plugin_api.mjs' +import { NakoValue, NakoCallback, NakoCallbackEvent, NakoSystem } from '../core/src/plugin_api.mjs' import { NakoBrowsesrSystem, IBrowserDocument, IBrowserWindow, IBrowserLocation } from './plugin_browser_api.mjs' import PartBrowserColor from './plugin_browser_color.mjs' @@ -214,6 +214,17 @@ const PluginBrowser = { } } } + // Elementのクラスに対してDOMに動的プロパティの取得と設定を適用するよう登録する + if (sys.__registPropAccessor && globalThis.Element) { + sys.__registPropAccessor(Element, + function (prop: string|string[], sys: NakoSystem):any { // @ts-ignore + return sys.__exec('DOM設定取得', [this as Element, prop, sys as NakoBrowsesrSystem]) + }, + function (prop: string|string[], value: object, sys: NakoSystem):any { // @ts-ignore + sys.__exec('DOM設定変更', [this as Element, prop, value, sys as NakoBrowsesrSystem]) + } + ) + } // DOM取得のために使う sys.__query = (dom: object|string, commandName: string, isGetFunc: boolean) => { // get element diff --git a/test/node/plugin_node_stdin_test.mjs b/test/node/plugin_node_stdin_test.mjs index 903aa2e6..6dbcf474 100644 --- a/test/node/plugin_node_stdin_test.mjs +++ b/test/node/plugin_node_stdin_test.mjs @@ -3,6 +3,7 @@ import assert from 'assert' import path from 'path' import fs from 'fs' import { execSync, spawnSync } from 'child_process' +import os from 'node:os' // __dirname のために import url from 'url' @@ -11,6 +12,8 @@ const debug = false const __filename = url.fileURLToPath(import.meta.url) const __dirname = path.dirname(__filename) +const execOption = os.platform() === 'win32' ? { shell: 'powershell.exe' } : undefined + // PATH const cnako3 = path.join(__dirname, '../../src/cnako3.mjs') @@ -18,7 +21,7 @@ const cnako3 = path.join(__dirname, '../../src/cnako3.mjs') describe('plugin_node_stdin_test(cnako)', () => { const cmp = (code, exRes, stdinStr) => { const cmd = `echo "${stdinStr}" | node ${cnako3} -e "${code}"` - const result = execSync(cmd).toString().trimEnd() + const result = execSync(cmd, execOption).toString().trimEnd() if (debug) { console.log('code=' + code) console.log('result=' + result)