react-pebble 0.1.0 → 0.1.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/dist/lib/compiler.cjs +2 -2
- package/dist/lib/compiler.cjs.map +1 -1
- package/dist/lib/compiler.js +18 -18
- package/dist/lib/compiler.js.map +1 -1
- package/package.json +1 -1
- package/scripts/compile-to-piu.ts +31 -9
- package/src/compiler/index.ts +3 -2
package/dist/lib/compiler.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`node:child_process`),t=require(`node:path`),n=require(`node:url`),r=require(`node:fs`);var i=(0,t.dirname)((0,n.fileURLToPath)({}.url));async function a(n){let a=n.logger??(()=>{}),o=n.projectRoot??process.cwd(),s=(0,t.
|
|
2
|
-
`).length} lines, buttons=${
|
|
1
|
+
Object.defineProperty(exports,Symbol.toStringTag,{value:`Module`});let e=require(`node:child_process`),t=require(`node:path`),n=require(`node:url`),r=require(`node:fs`);var i=(0,t.dirname)((0,n.fileURLToPath)({}.url));async function a(n){let a=n.logger??(()=>{}),o=n.projectRoot??process.cwd(),s=(0,t.resolve)(o,n.entry),c=(0,t.basename)(s).replace(/\.[jt]sx?$/,``),l=(0,t.resolve)(i,`../../scripts/compile-to-piu.ts`);if(!(0,r.existsSync)(l))throw Error(`Compiler script not found at ${l}`);a(`Compiling ${c}...`);let u={...process.env,EXAMPLE:s};n.settleMs&&(u.SETTLE_MS=String(n.settleMs)),n.platform&&(u.PEBBLE_PLATFORM=n.platform);let d,f;try{d=(0,e.execSync)(`npx tsx "${l}"`,{cwd:o,env:u,encoding:`utf-8`,timeout:3e4,stdio:[`pipe`,`pipe`,`pipe`]});try{f=(0,e.execSync)(`npx tsx "${l}" 2>&1 1>/dev/null`,{cwd:o,env:u,encoding:`utf-8`,timeout:3e4})}catch{f=``}}catch(e){let t=e;throw Error(`Compilation failed for ${c}: ${t.stderr??t.message}`)}let p=f.includes(`Button bindings discovered:`)&&!f.includes(`Button bindings discovered: 0`),m=[],h=f.match(/useMessage detected: key="([^"]+)"/);return h?.[1]&&m.push(h[1]),a(`Compiled ${c}: ${d.split(`
|
|
2
|
+
`).length} lines, buttons=${p}, messageKeys=[${m.join(`,`)}]`),{code:d,hasButtons:p,messageKeys:m,diagnostics:f}}exports.compileToPiu=a;
|
|
3
3
|
//# sourceMappingURL=compiler.cjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.cjs","names":[],"sources":["../../src/compiler/index.ts"],"sourcesContent":["/**\n * src/compiler/index.ts — react-pebble compile-to-piu library API.\n *\n * Wraps the compile-to-piu.ts script as a programmatic API. The script\n * runs as a subprocess (it uses module-level state that requires process\n * isolation). A future refactoring will inline the logic as a pure function.\n *\n * Usage:\n * import { compileToPiu } from 'react-pebble/compiler';\n * const result = await compileToPiu({ entry: 'examples/watchface.tsx' });\n * console.log(result.code); // piu Application.template JS\n */\n\nimport { execSync } from 'node:child_process';\nimport { resolve, dirname, basename } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { existsSync } from 'node:fs';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport interface CompileOptions {\n /** Path to the entry .tsx file (relative to cwd or absolute) */\n entry: string;\n /** Milliseconds to wait for async effects (useEffect/setTimeout) */\n settleMs?: number;\n /** Target platform (default: 'emery') */\n platform?: string;\n /** Logger for diagnostic messages */\n logger?: (msg: string) => void;\n /** Project root directory (default: process.cwd()) */\n projectRoot?: string;\n}\n\nexport interface CompileResult {\n /** The compiled piu JavaScript code */\n code: string;\n /** Whether the component uses useButton (needs watchapp mode) */\n hasButtons: boolean;\n /** Message keys used by useMessage hooks */\n messageKeys: string[];\n /** Diagnostic messages from the compiler */\n diagnostics: string;\n}\n\n/**\n * Compile a Preact component to piu Application.template code.\n *\n * Internally runs scripts/compile-to-piu.ts as a subprocess.\n */\nexport async function compileToPiu(options: CompileOptions): Promise<CompileResult> {\n const log = options.logger ?? (() => {});\n const projectRoot = options.projectRoot ?? process.cwd();\n\n // Resolve the entry
|
|
1
|
+
{"version":3,"file":"compiler.cjs","names":[],"sources":["../../src/compiler/index.ts"],"sourcesContent":["/**\n * src/compiler/index.ts — react-pebble compile-to-piu library API.\n *\n * Wraps the compile-to-piu.ts script as a programmatic API. The script\n * runs as a subprocess (it uses module-level state that requires process\n * isolation). A future refactoring will inline the logic as a pure function.\n *\n * Usage:\n * import { compileToPiu } from 'react-pebble/compiler';\n * const result = await compileToPiu({ entry: 'examples/watchface.tsx' });\n * console.log(result.code); // piu Application.template JS\n */\n\nimport { execSync } from 'node:child_process';\nimport { resolve, dirname, basename } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { existsSync } from 'node:fs';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport interface CompileOptions {\n /** Path to the entry .tsx file (relative to cwd or absolute) */\n entry: string;\n /** Milliseconds to wait for async effects (useEffect/setTimeout) */\n settleMs?: number;\n /** Target platform (default: 'emery') */\n platform?: string;\n /** Logger for diagnostic messages */\n logger?: (msg: string) => void;\n /** Project root directory (default: process.cwd()) */\n projectRoot?: string;\n}\n\nexport interface CompileResult {\n /** The compiled piu JavaScript code */\n code: string;\n /** Whether the component uses useButton (needs watchapp mode) */\n hasButtons: boolean;\n /** Message keys used by useMessage hooks */\n messageKeys: string[];\n /** Diagnostic messages from the compiler */\n diagnostics: string;\n}\n\n/**\n * Compile a Preact component to piu Application.template code.\n *\n * Internally runs scripts/compile-to-piu.ts as a subprocess.\n */\nexport async function compileToPiu(options: CompileOptions): Promise<CompileResult> {\n const log = options.logger ?? (() => {});\n const projectRoot = options.projectRoot ?? process.cwd();\n\n // Resolve the entry path — pass the full path so the script can find it\n // whether it's an internal example or an external project file\n const entryPath = resolve(projectRoot, options.entry);\n const exampleName = basename(entryPath).replace(/\\.[jt]sx?$/, '');\n\n // Find the compiler script\n const scriptPath = resolve(__dirname, '../../scripts/compile-to-piu.ts');\n if (!existsSync(scriptPath)) {\n throw new Error(`Compiler script not found at ${scriptPath}`);\n }\n\n log(`Compiling ${exampleName}...`);\n\n const env: Record<string, string> = {\n ...process.env as Record<string, string>,\n EXAMPLE: entryPath,\n };\n if (options.settleMs) {\n env.SETTLE_MS = String(options.settleMs);\n }\n if (options.platform) {\n env.PEBBLE_PLATFORM = options.platform;\n }\n\n // Run the compiler script and capture stdout (code) + stderr (diagnostics)\n let code: string;\n let diagnostics: string;\n try {\n code = execSync(`npx tsx \"${scriptPath}\"`, {\n cwd: projectRoot,\n env,\n encoding: 'utf-8',\n timeout: 30000,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n // Re-run to capture stderr separately (execSync doesn't give both easily)\n try {\n diagnostics = execSync(`npx tsx \"${scriptPath}\" 2>&1 1>/dev/null`, {\n cwd: projectRoot,\n env,\n encoding: 'utf-8',\n timeout: 30000,\n });\n } catch {\n diagnostics = '';\n }\n } catch (err) {\n const e = err as { stderr?: string; message?: string };\n throw new Error(`Compilation failed for ${exampleName}: ${e.stderr ?? e.message}`);\n }\n\n // Parse diagnostics to extract metadata\n const hasButtons = diagnostics.includes('Button bindings discovered:') &&\n !diagnostics.includes('Button bindings discovered: 0');\n const messageKeys: string[] = [];\n const msgMatch = diagnostics.match(/useMessage detected: key=\"([^\"]+)\"/);\n if (msgMatch?.[1]) messageKeys.push(msgMatch[1]);\n\n log(`Compiled ${exampleName}: ${code.split('\\n').length} lines, buttons=${hasButtons}, messageKeys=[${messageKeys.join(',')}]`);\n\n return { code, hasButtons, messageKeys, diagnostics };\n}\n"],"mappings":"yKAkBA,IAAM,GAAA,EAAA,EAAA,UAAA,EAAA,EAAA,eAAA,EAAA,CAA8C,IAAI,CAAC,CA+BzD,eAAsB,EAAa,EAAiD,CAClF,IAAM,EAAM,EAAQ,aAAiB,IAC/B,EAAc,EAAQ,aAAe,QAAQ,KAAK,CAIlD,GAAA,EAAA,EAAA,SAAoB,EAAa,EAAQ,MAAM,CAC/C,GAAA,EAAA,EAAA,UAAuB,EAAU,CAAC,QAAQ,aAAc,GAAG,CAG3D,GAAA,EAAA,EAAA,SAAqB,EAAW,kCAAkC,CACxE,GAAI,EAAA,EAAA,EAAA,YAAY,EAAW,CACzB,MAAU,MAAM,gCAAgC,IAAa,CAG/D,EAAI,aAAa,EAAY,KAAK,CAElC,IAAM,EAA8B,CAClC,GAAG,QAAQ,IACX,QAAS,EACV,CACG,EAAQ,WACV,EAAI,UAAY,OAAO,EAAQ,SAAS,EAEtC,EAAQ,WACV,EAAI,gBAAkB,EAAQ,UAIhC,IAAI,EACA,EACJ,GAAI,CACF,GAAA,EAAA,EAAA,UAAgB,YAAY,EAAW,GAAI,CACzC,IAAK,EACL,MACA,SAAU,QACV,QAAS,IACT,MAAO,CAAC,OAAQ,OAAQ,OAAO,CAChC,CAAC,CAEF,GAAI,CACF,GAAA,EAAA,EAAA,UAAuB,YAAY,EAAW,oBAAqB,CACjE,IAAK,EACL,MACA,SAAU,QACV,QAAS,IACV,CAAC,MACI,CACN,EAAc,UAET,EAAK,CACZ,IAAM,EAAI,EACV,MAAU,MAAM,0BAA0B,EAAY,IAAI,EAAE,QAAU,EAAE,UAAU,CAIpF,IAAM,EAAa,EAAY,SAAS,8BAA8B,EACpE,CAAC,EAAY,SAAS,gCAAgC,CAClD,EAAwB,EAAE,CAC1B,EAAW,EAAY,MAAM,qCAAqC,CAKxE,OAJI,IAAW,IAAI,EAAY,KAAK,EAAS,GAAG,CAEhD,EAAI,YAAY,EAAY,IAAI,EAAK,MAAM;EAAK,CAAC,OAAO,kBAAkB,EAAW,iBAAiB,EAAY,KAAK,IAAI,CAAC,GAAG,CAExH,CAAE,OAAM,aAAY,cAAa,cAAa"}
|
package/dist/lib/compiler.js
CHANGED
|
@@ -5,19 +5,19 @@ import { existsSync as a } from "node:fs";
|
|
|
5
5
|
//#region src/compiler/index.ts
|
|
6
6
|
var o = n(i(import.meta.url));
|
|
7
7
|
async function s(n) {
|
|
8
|
-
let i = n.logger ?? (() => {}), s = n.projectRoot ?? process.cwd(), c =
|
|
9
|
-
if (!a(
|
|
10
|
-
i(`Compiling ${
|
|
11
|
-
let
|
|
8
|
+
let i = n.logger ?? (() => {}), s = n.projectRoot ?? process.cwd(), c = r(s, n.entry), l = t(c).replace(/\.[jt]sx?$/, ""), u = r(o, "../../scripts/compile-to-piu.ts");
|
|
9
|
+
if (!a(u)) throw Error(`Compiler script not found at ${u}`);
|
|
10
|
+
i(`Compiling ${l}...`);
|
|
11
|
+
let d = {
|
|
12
12
|
...process.env,
|
|
13
13
|
EXAMPLE: c
|
|
14
14
|
};
|
|
15
|
-
n.settleMs && (
|
|
16
|
-
let
|
|
15
|
+
n.settleMs && (d.SETTLE_MS = String(n.settleMs)), n.platform && (d.PEBBLE_PLATFORM = n.platform);
|
|
16
|
+
let f, p;
|
|
17
17
|
try {
|
|
18
|
-
|
|
18
|
+
f = e(`npx tsx "${u}"`, {
|
|
19
19
|
cwd: s,
|
|
20
|
-
env:
|
|
20
|
+
env: d,
|
|
21
21
|
encoding: "utf-8",
|
|
22
22
|
timeout: 3e4,
|
|
23
23
|
stdio: [
|
|
@@ -27,25 +27,25 @@ async function s(n) {
|
|
|
27
27
|
]
|
|
28
28
|
});
|
|
29
29
|
try {
|
|
30
|
-
|
|
30
|
+
p = e(`npx tsx "${u}" 2>&1 1>/dev/null`, {
|
|
31
31
|
cwd: s,
|
|
32
|
-
env:
|
|
32
|
+
env: d,
|
|
33
33
|
encoding: "utf-8",
|
|
34
34
|
timeout: 3e4
|
|
35
35
|
});
|
|
36
36
|
} catch {
|
|
37
|
-
|
|
37
|
+
p = "";
|
|
38
38
|
}
|
|
39
39
|
} catch (e) {
|
|
40
40
|
let t = e;
|
|
41
|
-
throw Error(`Compilation failed for ${
|
|
41
|
+
throw Error(`Compilation failed for ${l}: ${t.stderr ?? t.message}`);
|
|
42
42
|
}
|
|
43
|
-
let
|
|
44
|
-
return
|
|
45
|
-
code:
|
|
46
|
-
hasButtons:
|
|
47
|
-
messageKeys:
|
|
48
|
-
diagnostics:
|
|
43
|
+
let m = p.includes("Button bindings discovered:") && !p.includes("Button bindings discovered: 0"), h = [], g = p.match(/useMessage detected: key="([^"]+)"/);
|
|
44
|
+
return g?.[1] && h.push(g[1]), i(`Compiled ${l}: ${f.split("\n").length} lines, buttons=${m}, messageKeys=[${h.join(",")}]`), {
|
|
45
|
+
code: f,
|
|
46
|
+
hasButtons: m,
|
|
47
|
+
messageKeys: h,
|
|
48
|
+
diagnostics: p
|
|
49
49
|
};
|
|
50
50
|
}
|
|
51
51
|
//#endregion
|
package/dist/lib/compiler.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"compiler.js","names":[],"sources":["../../src/compiler/index.ts"],"sourcesContent":["/**\n * src/compiler/index.ts — react-pebble compile-to-piu library API.\n *\n * Wraps the compile-to-piu.ts script as a programmatic API. The script\n * runs as a subprocess (it uses module-level state that requires process\n * isolation). A future refactoring will inline the logic as a pure function.\n *\n * Usage:\n * import { compileToPiu } from 'react-pebble/compiler';\n * const result = await compileToPiu({ entry: 'examples/watchface.tsx' });\n * console.log(result.code); // piu Application.template JS\n */\n\nimport { execSync } from 'node:child_process';\nimport { resolve, dirname, basename } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { existsSync } from 'node:fs';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport interface CompileOptions {\n /** Path to the entry .tsx file (relative to cwd or absolute) */\n entry: string;\n /** Milliseconds to wait for async effects (useEffect/setTimeout) */\n settleMs?: number;\n /** Target platform (default: 'emery') */\n platform?: string;\n /** Logger for diagnostic messages */\n logger?: (msg: string) => void;\n /** Project root directory (default: process.cwd()) */\n projectRoot?: string;\n}\n\nexport interface CompileResult {\n /** The compiled piu JavaScript code */\n code: string;\n /** Whether the component uses useButton (needs watchapp mode) */\n hasButtons: boolean;\n /** Message keys used by useMessage hooks */\n messageKeys: string[];\n /** Diagnostic messages from the compiler */\n diagnostics: string;\n}\n\n/**\n * Compile a Preact component to piu Application.template code.\n *\n * Internally runs scripts/compile-to-piu.ts as a subprocess.\n */\nexport async function compileToPiu(options: CompileOptions): Promise<CompileResult> {\n const log = options.logger ?? (() => {});\n const projectRoot = options.projectRoot ?? process.cwd();\n\n // Resolve the entry
|
|
1
|
+
{"version":3,"file":"compiler.js","names":[],"sources":["../../src/compiler/index.ts"],"sourcesContent":["/**\n * src/compiler/index.ts — react-pebble compile-to-piu library API.\n *\n * Wraps the compile-to-piu.ts script as a programmatic API. The script\n * runs as a subprocess (it uses module-level state that requires process\n * isolation). A future refactoring will inline the logic as a pure function.\n *\n * Usage:\n * import { compileToPiu } from 'react-pebble/compiler';\n * const result = await compileToPiu({ entry: 'examples/watchface.tsx' });\n * console.log(result.code); // piu Application.template JS\n */\n\nimport { execSync } from 'node:child_process';\nimport { resolve, dirname, basename } from 'node:path';\nimport { fileURLToPath } from 'node:url';\nimport { existsSync } from 'node:fs';\n\nconst __dirname = dirname(fileURLToPath(import.meta.url));\n\nexport interface CompileOptions {\n /** Path to the entry .tsx file (relative to cwd or absolute) */\n entry: string;\n /** Milliseconds to wait for async effects (useEffect/setTimeout) */\n settleMs?: number;\n /** Target platform (default: 'emery') */\n platform?: string;\n /** Logger for diagnostic messages */\n logger?: (msg: string) => void;\n /** Project root directory (default: process.cwd()) */\n projectRoot?: string;\n}\n\nexport interface CompileResult {\n /** The compiled piu JavaScript code */\n code: string;\n /** Whether the component uses useButton (needs watchapp mode) */\n hasButtons: boolean;\n /** Message keys used by useMessage hooks */\n messageKeys: string[];\n /** Diagnostic messages from the compiler */\n diagnostics: string;\n}\n\n/**\n * Compile a Preact component to piu Application.template code.\n *\n * Internally runs scripts/compile-to-piu.ts as a subprocess.\n */\nexport async function compileToPiu(options: CompileOptions): Promise<CompileResult> {\n const log = options.logger ?? (() => {});\n const projectRoot = options.projectRoot ?? process.cwd();\n\n // Resolve the entry path — pass the full path so the script can find it\n // whether it's an internal example or an external project file\n const entryPath = resolve(projectRoot, options.entry);\n const exampleName = basename(entryPath).replace(/\\.[jt]sx?$/, '');\n\n // Find the compiler script\n const scriptPath = resolve(__dirname, '../../scripts/compile-to-piu.ts');\n if (!existsSync(scriptPath)) {\n throw new Error(`Compiler script not found at ${scriptPath}`);\n }\n\n log(`Compiling ${exampleName}...`);\n\n const env: Record<string, string> = {\n ...process.env as Record<string, string>,\n EXAMPLE: entryPath,\n };\n if (options.settleMs) {\n env.SETTLE_MS = String(options.settleMs);\n }\n if (options.platform) {\n env.PEBBLE_PLATFORM = options.platform;\n }\n\n // Run the compiler script and capture stdout (code) + stderr (diagnostics)\n let code: string;\n let diagnostics: string;\n try {\n code = execSync(`npx tsx \"${scriptPath}\"`, {\n cwd: projectRoot,\n env,\n encoding: 'utf-8',\n timeout: 30000,\n stdio: ['pipe', 'pipe', 'pipe'],\n });\n // Re-run to capture stderr separately (execSync doesn't give both easily)\n try {\n diagnostics = execSync(`npx tsx \"${scriptPath}\" 2>&1 1>/dev/null`, {\n cwd: projectRoot,\n env,\n encoding: 'utf-8',\n timeout: 30000,\n });\n } catch {\n diagnostics = '';\n }\n } catch (err) {\n const e = err as { stderr?: string; message?: string };\n throw new Error(`Compilation failed for ${exampleName}: ${e.stderr ?? e.message}`);\n }\n\n // Parse diagnostics to extract metadata\n const hasButtons = diagnostics.includes('Button bindings discovered:') &&\n !diagnostics.includes('Button bindings discovered: 0');\n const messageKeys: string[] = [];\n const msgMatch = diagnostics.match(/useMessage detected: key=\"([^\"]+)\"/);\n if (msgMatch?.[1]) messageKeys.push(msgMatch[1]);\n\n log(`Compiled ${exampleName}: ${code.split('\\n').length} lines, buttons=${hasButtons}, messageKeys=[${messageKeys.join(',')}]`);\n\n return { code, hasButtons, messageKeys, diagnostics };\n}\n"],"mappings":";;;;;AAkBA,IAAM,IAAY,EAAQ,EAAc,OAAO,KAAK,IAAI,CAAC;AA+BzD,eAAsB,EAAa,GAAiD;CAClF,IAAM,IAAM,EAAQ,iBAAiB,KAC/B,IAAc,EAAQ,eAAe,QAAQ,KAAK,EAIlD,IAAY,EAAQ,GAAa,EAAQ,MAAM,EAC/C,IAAc,EAAS,EAAU,CAAC,QAAQ,cAAc,GAAG,EAG3D,IAAa,EAAQ,GAAW,kCAAkC;AACxE,KAAI,CAAC,EAAW,EAAW,CACzB,OAAU,MAAM,gCAAgC,IAAa;AAG/D,GAAI,aAAa,EAAY,KAAK;CAElC,IAAM,IAA8B;EAClC,GAAG,QAAQ;EACX,SAAS;EACV;AAID,CAHI,EAAQ,aACV,EAAI,YAAY,OAAO,EAAQ,SAAS,GAEtC,EAAQ,aACV,EAAI,kBAAkB,EAAQ;CAIhC,IAAI,GACA;AACJ,KAAI;AACF,MAAO,EAAS,YAAY,EAAW,IAAI;GACzC,KAAK;GACL;GACA,UAAU;GACV,SAAS;GACT,OAAO;IAAC;IAAQ;IAAQ;IAAO;GAChC,CAAC;AAEF,MAAI;AACF,OAAc,EAAS,YAAY,EAAW,qBAAqB;IACjE,KAAK;IACL;IACA,UAAU;IACV,SAAS;IACV,CAAC;UACI;AACN,OAAc;;UAET,GAAK;EACZ,IAAM,IAAI;AACV,QAAU,MAAM,0BAA0B,EAAY,IAAI,EAAE,UAAU,EAAE,UAAU;;CAIpF,IAAM,IAAa,EAAY,SAAS,8BAA8B,IACpE,CAAC,EAAY,SAAS,gCAAgC,EAClD,IAAwB,EAAE,EAC1B,IAAW,EAAY,MAAM,qCAAqC;AAKxE,QAJI,IAAW,MAAI,EAAY,KAAK,EAAS,GAAG,EAEhD,EAAI,YAAY,EAAY,IAAI,EAAK,MAAM,KAAK,CAAC,OAAO,kBAAkB,EAAW,iBAAiB,EAAY,KAAK,IAAI,CAAC,GAAG,EAExH;EAAE;EAAM;EAAY;EAAa;EAAa"}
|
package/package.json
CHANGED
|
@@ -36,18 +36,31 @@ const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
|
36
36
|
// Dynamic example import
|
|
37
37
|
// ---------------------------------------------------------------------------
|
|
38
38
|
|
|
39
|
-
const
|
|
39
|
+
const exampleInput = process.env.EXAMPLE ?? 'watchface';
|
|
40
40
|
const settleMs = Number(process.env.SETTLE_MS ?? '0');
|
|
41
41
|
const platform = process.env.PEBBLE_PLATFORM ?? 'emery';
|
|
42
42
|
const settle = () =>
|
|
43
43
|
settleMs > 0 ? new Promise<void>((r) => setTimeout(r, settleMs)) : Promise.resolve();
|
|
44
44
|
|
|
45
45
|
// Set platform screen dimensions before importing the example
|
|
46
|
-
// (so SCREEN.width/height are correct when the component renders)
|
|
47
46
|
import { _setPlatform, SCREEN } from '../src/platform.js';
|
|
48
47
|
_setPlatform(platform);
|
|
49
48
|
|
|
50
|
-
|
|
49
|
+
// Resolve the entry: could be a bare name (e.g., "watchface") for internal examples,
|
|
50
|
+
// or an absolute/relative path (e.g., "/tmp/my-app/src/App.tsx") for external projects.
|
|
51
|
+
let entryPath: string;
|
|
52
|
+
let exampleName: string;
|
|
53
|
+
if (exampleInput.includes('/') || exampleInput.includes('\\')) {
|
|
54
|
+
// Absolute or relative path — resolve from cwd
|
|
55
|
+
entryPath = resolve(exampleInput);
|
|
56
|
+
exampleName = entryPath.replace(/\.[jt]sx?$/, '').split('/').pop()!;
|
|
57
|
+
} else {
|
|
58
|
+
// Bare name — look in ../examples/
|
|
59
|
+
entryPath = resolve(__dirname, '..', 'examples', `${exampleInput}.tsx`);
|
|
60
|
+
exampleName = exampleInput;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const exampleMod = await import(entryPath);
|
|
51
64
|
const exampleMain: (...args: unknown[]) => ReturnType<typeof render> =
|
|
52
65
|
exampleMod.main ?? exampleMod.default;
|
|
53
66
|
|
|
@@ -165,8 +178,17 @@ const buttonBindings: ButtonBinding[] = [];
|
|
|
165
178
|
* Parse an example source file into a TypeScript AST SourceFile.
|
|
166
179
|
*/
|
|
167
180
|
function parseExampleSource(exName: string): ts.SourceFile | null {
|
|
168
|
-
|
|
169
|
-
|
|
181
|
+
// If exName is an absolute path, try it directly
|
|
182
|
+
if (exName.startsWith('/')) {
|
|
183
|
+
try {
|
|
184
|
+
const source = readFileSync(exName, 'utf-8');
|
|
185
|
+
return ts.createSourceFile(exName, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
186
|
+
} catch { /* fall through to extension search */ }
|
|
187
|
+
}
|
|
188
|
+
for (const ext of ['.tsx', '.ts', '.jsx', '']) {
|
|
189
|
+
const srcPath = exName.startsWith('/')
|
|
190
|
+
? `${exName}${ext}`
|
|
191
|
+
: resolve(__dirname, '..', 'examples', `${exName}${ext}`);
|
|
170
192
|
try {
|
|
171
193
|
const source = readFileSync(srcPath, 'utf-8');
|
|
172
194
|
return ts.createSourceFile(srcPath, source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TSX);
|
|
@@ -248,8 +270,8 @@ function buildSetterSlotMap(exName: string): Map<string, number> {
|
|
|
248
270
|
return map;
|
|
249
271
|
}
|
|
250
272
|
|
|
251
|
-
const setterSlotMap = buildSetterSlotMap(
|
|
252
|
-
const listInfo = detectListPatterns(
|
|
273
|
+
const setterSlotMap = buildSetterSlotMap(entryPath);
|
|
274
|
+
const listInfo = detectListPatterns(entryPath);
|
|
253
275
|
if (listInfo) {
|
|
254
276
|
process.stderr.write(`List detected: array="${listInfo.dataArrayName}" visible=${listInfo.visibleCount} labelsPerItem=${listInfo.labelsPerItem}\n`);
|
|
255
277
|
if (listInfo.dataArrayValues) process.stderr.write(` values: ${JSON.stringify(listInfo.dataArrayValues)}\n`);
|
|
@@ -298,7 +320,7 @@ function detectUseMessage(exName: string): MessageInfo | null {
|
|
|
298
320
|
return { key, mockDataArrayName };
|
|
299
321
|
}
|
|
300
322
|
|
|
301
|
-
const messageInfo = detectUseMessage(
|
|
323
|
+
const messageInfo = detectUseMessage(entryPath);
|
|
302
324
|
if (messageInfo) {
|
|
303
325
|
process.stderr.write(`useMessage detected: key="${messageInfo.key}"${messageInfo.mockDataArrayName ? ` mockData=${messageInfo.mockDataArrayName}` : ''}\n`);
|
|
304
326
|
}
|
|
@@ -879,7 +901,7 @@ let listScrollSlotIndex = -1;
|
|
|
879
901
|
|
|
880
902
|
// Install interceptors BEFORE any rendering
|
|
881
903
|
installUseStateInterceptor();
|
|
882
|
-
extractButtonBindingsFromSource(
|
|
904
|
+
extractButtonBindingsFromSource(entryPath);
|
|
883
905
|
|
|
884
906
|
// Create BOTH test dates with the REAL Date before any mocking.
|
|
885
907
|
const OrigDate = globalThis.Date;
|
package/src/compiler/index.ts
CHANGED
|
@@ -51,7 +51,8 @@ export async function compileToPiu(options: CompileOptions): Promise<CompileResu
|
|
|
51
51
|
const log = options.logger ?? (() => {});
|
|
52
52
|
const projectRoot = options.projectRoot ?? process.cwd();
|
|
53
53
|
|
|
54
|
-
// Resolve the entry
|
|
54
|
+
// Resolve the entry path — pass the full path so the script can find it
|
|
55
|
+
// whether it's an internal example or an external project file
|
|
55
56
|
const entryPath = resolve(projectRoot, options.entry);
|
|
56
57
|
const exampleName = basename(entryPath).replace(/\.[jt]sx?$/, '');
|
|
57
58
|
|
|
@@ -65,7 +66,7 @@ export async function compileToPiu(options: CompileOptions): Promise<CompileResu
|
|
|
65
66
|
|
|
66
67
|
const env: Record<string, string> = {
|
|
67
68
|
...process.env as Record<string, string>,
|
|
68
|
-
EXAMPLE:
|
|
69
|
+
EXAMPLE: entryPath,
|
|
69
70
|
};
|
|
70
71
|
if (options.settleMs) {
|
|
71
72
|
env.SETTLE_MS = String(options.settleMs);
|