@octane-xplat/workshop 0.0.0-nightly.g2e22171
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/LICENSE +21 -0
- package/MOBILE.md +143 -0
- package/README.md +307 -0
- package/dist/node/index.js +50 -0
- package/package.json +127 -0
- package/src/catalog.ts +58 -0
- package/src/contract.ts +257 -0
- package/src/controls.ts +159 -0
- package/src/discover.mjs +584 -0
- package/src/errors.ts +47 -0
- package/src/fixture.ts +158 -0
- package/src/index.ts +6 -0
- package/src/macos/controller.ts +170 -0
- package/src/macos/index.macos.ts +2 -0
- package/src/macos/shell.macos.mjs +673 -0
- package/src/macos/stage.macos.ts +182 -0
- package/src/macos-node.mjs +95 -0
- package/src/macos-vite.mjs +47 -0
- package/src/mobile/controller.ts +134 -0
- package/src/mobile/entry.mobile.ts +607 -0
- package/src/mobile/index.mobile.ts +3 -0
- package/src/mobile/mount.mobile.ts +60 -0
- package/src/mobile/tree.mobile.tsrx +17 -0
- package/src/mobile-node.mjs +126 -0
- package/src/mobile-regex.mjs +60 -0
- package/src/node.d.ts +65 -0
- package/src/node.mjs +536 -0
- package/src/session.ts +520 -0
- package/src/vite-mobile.d.ts +21 -0
- package/src/vite-mobile.mjs +101 -0
- package/src/vite.d.ts +11 -0
- package/src/vite.mjs +315 -0
- package/src/web/entry.web.ts +270 -0
- package/src/web/index.web.ts +7 -0
- package/src/web/mount.web.ts +86 -0
- package/src/web/shell.css +449 -0
- package/src/web/shell.web.tsrx +759 -0
- package/src/windows/preflight.mjs +113 -0
- package/types/generated/.tsrx-typegen-manifest.json +24 -0
- package/types/generated/catalog.d.ts +30 -0
- package/types/generated/contract.d.ts +145 -0
- package/types/generated/controls.d.ts +28 -0
- package/types/generated/errors.d.ts +13 -0
- package/types/generated/fixture.d.ts +53 -0
- package/types/generated/index.d.ts +6 -0
- package/types/generated/macos/controller.d.ts +52 -0
- package/types/generated/macos/index.macos.d.ts +2 -0
- package/types/generated/macos/stage.macos.d.ts +10 -0
- package/types/generated/mobile/controller.d.ts +31 -0
- package/types/generated/mobile/entry.mobile.d.ts +22 -0
- package/types/generated/mobile/index.mobile.d.ts +3 -0
- package/types/generated/mobile/mount.mobile.d.ts +4 -0
- package/types/generated/mobile/tree.mobile.d.ts +4 -0
- package/types/generated/session.d.ts +84 -0
- package/types/generated/web/entry.web.d.ts +53 -0
- package/types/generated/web/index.web.d.ts +7 -0
- package/types/generated/web/mount.web.d.ts +2 -0
- package/types/generated/web/shell.web.d.ts +4 -0
|
@@ -0,0 +1,126 @@
|
|
|
1
|
+
import { createRequire } from 'node:module'
|
|
2
|
+
import { existsSync, readFileSync } from 'node:fs'
|
|
3
|
+
import { dirname, join, resolve } from 'node:path'
|
|
4
|
+
import { spawn } from 'node:child_process'
|
|
5
|
+
|
|
6
|
+
const CONFIGS = [
|
|
7
|
+
'vite.config.native.mts',
|
|
8
|
+
'vite.config.native.ts',
|
|
9
|
+
'vite.config.mts',
|
|
10
|
+
'vite.config.ts',
|
|
11
|
+
'vite.config.mjs',
|
|
12
|
+
]
|
|
13
|
+
|
|
14
|
+
export function mobilePrerequisites(root, target, host = process.platform, env = process.env) {
|
|
15
|
+
const req = createRequire(join(root, 'package.json'))
|
|
16
|
+
const installed = (name) => {
|
|
17
|
+
try {
|
|
18
|
+
req.resolve(name)
|
|
19
|
+
return true
|
|
20
|
+
} catch {
|
|
21
|
+
return false
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const configFile = CONFIGS.map((name) => join(root, name)).find(existsSync)
|
|
26
|
+
const requirements = {
|
|
27
|
+
'nativescript.config.ts': existsSync(join(root, 'nativescript.config.ts')),
|
|
28
|
+
'native workshop Vite setup': Boolean(
|
|
29
|
+
configFile && /withWorkshopMobile/.test(readFileSync(configFile, 'utf8')),
|
|
30
|
+
),
|
|
31
|
+
'@nativescript/core': installed('@nativescript/core'),
|
|
32
|
+
'@nativescript-community/octane': installed('@nativescript-community/octane'),
|
|
33
|
+
'@nativescript-community/vite-octane': installed('@nativescript-community/vite-octane'),
|
|
34
|
+
'@valor/nativescript-websockets': installed('@valor/nativescript-websockets'),
|
|
35
|
+
'nativescript CLI': installed('nativescript'),
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
if (target === 'ios') {
|
|
39
|
+
requirements['macOS / Xcode host'] = host === 'darwin' && existsSync('/Applications/Xcode.app')
|
|
40
|
+
} else {
|
|
41
|
+
requirements['Android SDK directory'] = Boolean(
|
|
42
|
+
(env.ANDROID_HOME || env.ANDROID_SDK_ROOT) &&
|
|
43
|
+
existsSync(env.ANDROID_HOME || env.ANDROID_SDK_ROOT),
|
|
44
|
+
)
|
|
45
|
+
|
|
46
|
+
requirements['JAVA_HOME directory'] = Boolean(env.JAVA_HOME && existsSync(env.JAVA_HOME))
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return {
|
|
50
|
+
backend: 'nativescript (Octane universal renderer)',
|
|
51
|
+
requirements,
|
|
52
|
+
status:
|
|
53
|
+
target === 'ios' && host !== 'darwin'
|
|
54
|
+
? 'remote-host-required'
|
|
55
|
+
: Object.values(requirements).every(Boolean)
|
|
56
|
+
? 'unqualified-backend'
|
|
57
|
+
: 'missing-prerequisites',
|
|
58
|
+
note: 'Mobile adapter installed; actual-host lifecycle, touch, keyboard, screen-reader and IME qualification remain open. Doctor does not launch or select a device.',
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
export function mobileLaunchSpec({ root, target, device, config, story }) {
|
|
63
|
+
if (!['ios', 'android'].includes(target)) {
|
|
64
|
+
throw new Error('Expected ios or android')
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!device || typeof device !== 'string' || device.startsWith('-')) {
|
|
68
|
+
throw new Error(
|
|
69
|
+
'Mobile workshop requires --device <device-id>; it never chooses or boots a device implicitly',
|
|
70
|
+
)
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
const req = createRequire(join(root, 'package.json'))
|
|
74
|
+
const packageFile = req.resolve('nativescript/package.json')
|
|
75
|
+
const manifest = JSON.parse(readFileSync(packageFile, 'utf8'))
|
|
76
|
+
const binary =
|
|
77
|
+
typeof manifest.bin === 'string' ? manifest.bin : (manifest.bin.ns ?? manifest.bin.nativescript)
|
|
78
|
+
|
|
79
|
+
if (!binary) {
|
|
80
|
+
throw new Error('Installed NativeScript CLI has no ns binary')
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return {
|
|
84
|
+
command: process.execPath,
|
|
85
|
+
args: [resolve(dirname(packageFile), binary), 'run', target, '--device', device],
|
|
86
|
+
options: {
|
|
87
|
+
cwd: root,
|
|
88
|
+
stdio: 'inherit',
|
|
89
|
+
shell: false,
|
|
90
|
+
env: {
|
|
91
|
+
...process.env,
|
|
92
|
+
XPLAT_WORKSHOP_TARGET: target,
|
|
93
|
+
XPLAT_WORKSHOP_CONFIG: JSON.stringify(config),
|
|
94
|
+
XPLAT_WORKSHOP_STORY: story ?? '',
|
|
95
|
+
},
|
|
96
|
+
},
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
export async function launchMobile(options) {
|
|
101
|
+
const spec = mobileLaunchSpec(options)
|
|
102
|
+
const child = spawn(spec.command, spec.args, spec.options)
|
|
103
|
+
const interrupt = () => child.kill('SIGINT')
|
|
104
|
+
const terminate = () => child.kill('SIGTERM')
|
|
105
|
+
process.on('SIGINT', interrupt)
|
|
106
|
+
process.on('SIGTERM', terminate)
|
|
107
|
+
try {
|
|
108
|
+
await new Promise((resolve, reject) => {
|
|
109
|
+
child.once('error', reject)
|
|
110
|
+
child.once('exit', (code, signal) =>
|
|
111
|
+
code === 0
|
|
112
|
+
? resolve()
|
|
113
|
+
: reject(
|
|
114
|
+
new Error(
|
|
115
|
+
`NativeScript workshop ${options.target} exited ${signal ?? code}; check launch logs and restart the target`,
|
|
116
|
+
),
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
})
|
|
120
|
+
} finally {
|
|
121
|
+
process.off('SIGINT', interrupt)
|
|
122
|
+
process.off('SIGTERM', terminate)
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
return { target: options.target, exited: true }
|
|
126
|
+
}
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { transformAsync, types } from '@babel/core'
|
|
2
|
+
import unicodeProperties from '@babel/plugin-transform-unicode-property-regex'
|
|
3
|
+
|
|
4
|
+
// Compatibility approach shared with apps/mobile/visual-regex.mjs; no testing-host dependency.
|
|
5
|
+
/** Compile Unicode properties for the pinned iOS runtime without changing globals. */
|
|
6
|
+
export function transformMobileRegex(code, filename = 'workshop-host.mjs') {
|
|
7
|
+
return transformAsync(code, {
|
|
8
|
+
filename,
|
|
9
|
+
configFile: false,
|
|
10
|
+
babelrc: false,
|
|
11
|
+
sourceMaps: true,
|
|
12
|
+
plugins: [
|
|
13
|
+
// Storybook also embeds constant RegExp constructors. Turn only unshadowed
|
|
14
|
+
// built-in constructors into literals for Babel's standard regex transform.
|
|
15
|
+
() => ({
|
|
16
|
+
visitor: {
|
|
17
|
+
NewExpression(path) {
|
|
18
|
+
const node = path.node
|
|
19
|
+
if (
|
|
20
|
+
!types.isIdentifier(node.callee, { name: 'RegExp' }) ||
|
|
21
|
+
path.scope.getBinding('RegExp') ||
|
|
22
|
+
node.arguments.length !== 2
|
|
23
|
+
) {
|
|
24
|
+
return
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
const [pattern, flags] = node.arguments
|
|
28
|
+
if (
|
|
29
|
+
types.isStringLiteral(pattern) &&
|
|
30
|
+
types.isStringLiteral(flags) &&
|
|
31
|
+
flags.value.includes('u') &&
|
|
32
|
+
/\\[pP]\{/.test(pattern.value)
|
|
33
|
+
) {
|
|
34
|
+
path.replaceWith(types.regExpLiteral(pattern.value, flags.value))
|
|
35
|
+
}
|
|
36
|
+
},
|
|
37
|
+
},
|
|
38
|
+
}),
|
|
39
|
+
unicodeProperties.default ?? unicodeProperties,
|
|
40
|
+
],
|
|
41
|
+
})
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
export function mobileRegexPlugin() {
|
|
45
|
+
return {
|
|
46
|
+
name: 'xplat-workshop-mobile-unicode-regex',
|
|
47
|
+
async transform(code, id) {
|
|
48
|
+
if (!/\\[pP]\{/.test(code) || !/\.[cm]?js(?:\?|$)/.test(id)) {
|
|
49
|
+
return null
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const result = await transformMobileRegex(code, id.split('?')[0])
|
|
53
|
+
return result ? { code: result.code, map: result.map } : null
|
|
54
|
+
},
|
|
55
|
+
async renderChunk(code, chunk) {
|
|
56
|
+
const result = await transformMobileRegex(code, chunk.fileName)
|
|
57
|
+
return result ? { code: result.code, map: result.map } : null
|
|
58
|
+
},
|
|
59
|
+
}
|
|
60
|
+
}
|
package/src/node.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
export interface WorkshopListResult {
|
|
2
|
+
entries: unknown[]
|
|
3
|
+
diagnostics: { file: string; exportName?: string; message: string }[]
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
export interface WorkshopDoctorReport {
|
|
7
|
+
root: string
|
|
8
|
+
targets: Record<
|
|
9
|
+
string,
|
|
10
|
+
{
|
|
11
|
+
backend: string
|
|
12
|
+
requirements: Record<string, boolean>
|
|
13
|
+
status: string
|
|
14
|
+
note?: string
|
|
15
|
+
executionHost?: { required: string; current: string; reachable: boolean }
|
|
16
|
+
qualification?: 'unverified'
|
|
17
|
+
}
|
|
18
|
+
>
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class WorkshopUsageError extends Error {}
|
|
22
|
+
export declare function workshopList(options?: {
|
|
23
|
+
cwd?: string
|
|
24
|
+
target?: string
|
|
25
|
+
json?: boolean
|
|
26
|
+
}): Promise<WorkshopListResult>
|
|
27
|
+
|
|
28
|
+
export declare function workshopDoctor(options?: {
|
|
29
|
+
cwd?: string
|
|
30
|
+
json?: boolean
|
|
31
|
+
}): Promise<WorkshopDoctorReport>
|
|
32
|
+
|
|
33
|
+
export declare function workshopInit(options?: {
|
|
34
|
+
cwd?: string
|
|
35
|
+
scripts?: boolean
|
|
36
|
+
}): Promise<{ created: string[]; skipped: string[] }>
|
|
37
|
+
|
|
38
|
+
export declare function workshopDev(options?: {
|
|
39
|
+
cwd?: string
|
|
40
|
+
target?: string
|
|
41
|
+
story?: string
|
|
42
|
+
port?: number
|
|
43
|
+
device?: string
|
|
44
|
+
}): Promise<unknown>
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Shared dev-server seam for DOM targets — the caller owns process
|
|
48
|
+
* lifecycle. Exported so qualification harnesses can boot the exact
|
|
49
|
+
* production wiring.
|
|
50
|
+
*/
|
|
51
|
+
export declare function startWorkshopServer(options?: {
|
|
52
|
+
root?: string
|
|
53
|
+
config?: object
|
|
54
|
+
target?: string
|
|
55
|
+
story?: string
|
|
56
|
+
port?: number
|
|
57
|
+
}): Promise<{ server: unknown; url: string }>
|
|
58
|
+
|
|
59
|
+
/** Linux host prerequisites as a missing-item list (empty when satisfied). */
|
|
60
|
+
export declare function linuxMissingPrerequisites(): string[]
|
|
61
|
+
|
|
62
|
+
export declare function findConfigFile(root: string): string | null
|
|
63
|
+
export declare function loadWorkshopConfig(
|
|
64
|
+
root: string,
|
|
65
|
+
): Promise<{ config: object; file: string | null }>
|