create-octane-xplat 0.14.0 → 0.16.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.
- package/README.md +78 -1
- package/compatibility.json +199 -0
- package/compatibility.ts +109 -0
- package/dist/compatibility.js +66 -0
- package/dist/index.js +132 -0
- package/dist/scaffold.js +439 -0
- package/index.ts +198 -0
- package/library-template/AGENTS.md +18 -0
- package/{LICENSE → library-template/LICENSE} +6 -6
- package/library-template/README.md +84 -0
- package/library-template/gitignore +5 -0
- package/library-template/package.json +92 -0
- package/library-template/pnpm-workspace.yaml +156 -0
- package/library-template/src/Badge.tsx +21 -0
- package/library-template/src/Badge.web.tsx +21 -0
- package/library-template/src/index.ts +3 -0
- package/library-template/src/index.web.ts +3 -0
- package/library-template/src/normalizeBadgeLabel.ts +12 -0
- package/library-template/src/props.ts +14 -0
- package/library-template/tests/normalizeBadgeLabel.test.ts +6 -0
- package/library-template/tests/packed-consumer.mjs +156 -0
- package/library-template/tsconfig.envs.json +17 -0
- package/library-template/tsconfig.json +27 -0
- package/library-template/tsconfig.types.json +11 -0
- package/library-template/tsrx-typegen.json +16 -0
- package/package.json +27 -8
- package/{scaffold.mjs → scaffold.ts} +149 -47
- package/template/.agents/skills/xplat/SKILL.md +11 -3
- package/template/.agents/skills/xplat/references/components.md +2 -2
- package/template/.agents/skills/xplat/references/navigation.md +9 -5
- package/template/.agents/skills/xplat/references/platform.md +2 -2
- package/template/AGENTS.md +47 -0
- package/template/App_Resources/Android/app.gradle +1 -1
- package/template/package.json +35 -32
- package/template/pnpm-workspace.yaml +73 -11
- package/template/src/app.spec.tsrx +80 -2
- package/template/src/app.web.test.tsx +20 -0
- package/template/src/failure-reporting.spec.ts +11 -0
- package/template/src/main.web.tsrx +1 -0
- package/template/src/native-runtime.spec.ts +18 -0
- package/template/src/test-setup.web.ts +17 -0
- package/template/tsconfig.json +32 -8
- package/template/vite.config.ts +2 -2
- package/template/vitest.web.config.mts +13 -0
- package/index.mjs +0 -129
- package/template/.oxlintrc.json +0 -25
- package/template/tsconfig.native.json +0 -18
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
# octane-xplat-library
|
|
2
|
+
|
|
3
|
+
A cross-platform component library for Octane Xplat. The starter includes a
|
|
4
|
+
small `Badge` component and a packed-consumer check so you can build a package
|
|
5
|
+
and check the artifact that will be published.
|
|
6
|
+
|
|
7
|
+
## Start here
|
|
8
|
+
|
|
9
|
+
Install this package in an Octane Xplat app:
|
|
10
|
+
|
|
11
|
+
```sh
|
|
12
|
+
pnpm add octane-xplat-library
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Render the example component from your app:
|
|
16
|
+
|
|
17
|
+
```tsx
|
|
18
|
+
import { Badge } from 'octane-xplat-library'
|
|
19
|
+
|
|
20
|
+
export function Welcome() {
|
|
21
|
+
return <Badge label="Ready" />
|
|
22
|
+
}
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## Develop and check
|
|
26
|
+
|
|
27
|
+
Run these commands from the package directory:
|
|
28
|
+
|
|
29
|
+
```sh
|
|
30
|
+
pnpm typecheck
|
|
31
|
+
pnpm lint
|
|
32
|
+
pnpm lint:fix
|
|
33
|
+
pnpm test
|
|
34
|
+
pnpm typegen
|
|
35
|
+
pnpm test:packed
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
Linting uses the CLI's bundled framework defaults. Apply safe lint fixes with
|
|
39
|
+
`lint:fix`; use `format` to format source and `fmt --check` to check formatting
|
|
40
|
+
without changing files:
|
|
41
|
+
|
|
42
|
+
```sh
|
|
43
|
+
pnpm format
|
|
44
|
+
pnpm exec xplat fmt --check
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The package publishes authored source for the app's bundler to compile.
|
|
48
|
+
`pnpm typegen` generates `.d.ts` files so consumers' type checkers use
|
|
49
|
+
declarations. `pnpm test:packed` packs the package, places that artifact into
|
|
50
|
+
small web and native TypeScript consumers, and checks both export conditions.
|
|
51
|
+
|
|
52
|
+
The package sets `nodeLinker: hoisted` in `pnpm-workspace.yaml` because the
|
|
53
|
+
NativeScript bundler expects a flat dependency tree.
|
|
54
|
+
|
|
55
|
+
Its `catalog:xplat` build dependencies and patches follow one framework
|
|
56
|
+
compatibility set. Update that set together; consumer `peerDependencies`
|
|
57
|
+
ranges are preserved for you to maintain:
|
|
58
|
+
|
|
59
|
+
```sh
|
|
60
|
+
pnpm dlx @octane-xplat/cli@latest upgrade --check
|
|
61
|
+
pnpm dlx @octane-xplat/cli@latest upgrade
|
|
62
|
+
pnpm xplat doctor
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
## Platform files
|
|
66
|
+
|
|
67
|
+
`src/Badge.tsx` is the shared iOS and Android implementation. The
|
|
68
|
+
`src/Badge.web.tsx` sibling supplies the web implementation. Keep their props
|
|
69
|
+
and exports aligned in `src/props.ts` and the two `src/index` barrels. Add
|
|
70
|
+
`.ios.tsx`, `.android.tsx`, or `.mobile.tsx` files only when a behavior needs
|
|
71
|
+
to differ on those targets.
|
|
72
|
+
|
|
73
|
+
The starter supports web, iOS, and Android. It does not include app shells or
|
|
74
|
+
desktop runtime entries. If the package uses a NativeScript plugin, declare it
|
|
75
|
+
as a runtime dependency and add the plugin's required platform files and
|
|
76
|
+
metadata to this package.
|
|
77
|
+
|
|
78
|
+
## Prepare to publish
|
|
79
|
+
|
|
80
|
+
Before publishing, replace the generated package name and repository metadata
|
|
81
|
+
in `package.json`, fill in the year and copyright holder in `LICENSE`, and
|
|
82
|
+
confirm that every runtime import is declared. `pnpm test:packed` checks the
|
|
83
|
+
package tarball's web and native type exports; it does not build or launch a
|
|
84
|
+
consuming app on a device.
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "octane-xplat-library",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "A cross-platform component library for Octane Xplat",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"android",
|
|
7
|
+
"cross-platform",
|
|
8
|
+
"ios",
|
|
9
|
+
"octane",
|
|
10
|
+
"octane-xplat",
|
|
11
|
+
"ui",
|
|
12
|
+
"web"
|
|
13
|
+
],
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"repository": {
|
|
16
|
+
"type": "git",
|
|
17
|
+
"url": "https://github.com/your-org/your-library",
|
|
18
|
+
"directory": "."
|
|
19
|
+
},
|
|
20
|
+
"files": [
|
|
21
|
+
"src",
|
|
22
|
+
"types",
|
|
23
|
+
"LICENSE"
|
|
24
|
+
],
|
|
25
|
+
"type": "module",
|
|
26
|
+
"exports": {
|
|
27
|
+
".": {
|
|
28
|
+
"macos": null,
|
|
29
|
+
"linux": null,
|
|
30
|
+
"windows": null,
|
|
31
|
+
"web": {
|
|
32
|
+
"types": "./types/index.web.d.ts",
|
|
33
|
+
"default": "./src/index.web.ts"
|
|
34
|
+
},
|
|
35
|
+
"native": {
|
|
36
|
+
"types": "./types/index.d.ts",
|
|
37
|
+
"default": "./src/index.ts"
|
|
38
|
+
},
|
|
39
|
+
"types": "./types/index.d.ts",
|
|
40
|
+
"default": "./src/index.ts"
|
|
41
|
+
}
|
|
42
|
+
},
|
|
43
|
+
"publishConfig": {
|
|
44
|
+
"access": "public"
|
|
45
|
+
},
|
|
46
|
+
"scripts": {
|
|
47
|
+
"typegen": "tsrx-typegen --project tsconfig.types.json",
|
|
48
|
+
"typecheck": "xplat typecheck",
|
|
49
|
+
"lint": "xplat lint",
|
|
50
|
+
"lint:fix": "xplat lint --fix",
|
|
51
|
+
"test": "vitest run",
|
|
52
|
+
"test:packed": "node tests/packed-consumer.mjs",
|
|
53
|
+
"prepack": "pnpm typegen && tsrx-typegen --pack-check",
|
|
54
|
+
"pack:check": "pnpm test:packed",
|
|
55
|
+
"format": "xplat fmt"
|
|
56
|
+
},
|
|
57
|
+
"devDependencies": {
|
|
58
|
+
"@nativescript-community/octane": "catalog:xplat",
|
|
59
|
+
"@nativescript/core": "catalog:xplat",
|
|
60
|
+
"@nativescript/types": "catalog:xplat",
|
|
61
|
+
"@octane-xplat/cli": "catalog:xplat",
|
|
62
|
+
"@octane-xplat/jsx": "catalog:xplat",
|
|
63
|
+
"@octane-xplat/ui": "catalog:xplat",
|
|
64
|
+
"@octanejs/vite-plugin": "catalog:xplat",
|
|
65
|
+
"@tsrx/oxc": "catalog:xplat",
|
|
66
|
+
"@tsrx/typescript-plugin": "catalog:xplat",
|
|
67
|
+
"octane": "catalog:xplat",
|
|
68
|
+
"tsrx-typegen": "catalog:xplat",
|
|
69
|
+
"typescript": "catalog:xplat",
|
|
70
|
+
"vite": "catalog:xplat",
|
|
71
|
+
"vitest": "catalog:xplat"
|
|
72
|
+
},
|
|
73
|
+
"peerDependencies": {
|
|
74
|
+
"@nativescript-community/octane": ">=0.2.1 <1",
|
|
75
|
+
"@nativescript/core": ">=9.1.0 <10",
|
|
76
|
+
"@octane-xplat/jsx": "^0.16.0",
|
|
77
|
+
"@octane-xplat/ui": "^0.16.0",
|
|
78
|
+
"octane": ">=0.6.3 <1"
|
|
79
|
+
},
|
|
80
|
+
"peerDependenciesMeta": {
|
|
81
|
+
"@nativescript-community/octane": {
|
|
82
|
+
"optional": true
|
|
83
|
+
},
|
|
84
|
+
"@nativescript/core": {
|
|
85
|
+
"optional": true
|
|
86
|
+
}
|
|
87
|
+
},
|
|
88
|
+
"packageManager": "pnpm@11.24.0",
|
|
89
|
+
"engines": {
|
|
90
|
+
"node": ">=22.18.0"
|
|
91
|
+
}
|
|
92
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
# NativeScript's bundler resolves dependencies from the flat package tree.
|
|
2
|
+
nodeLinker: hoisted
|
|
3
|
+
allowBuilds:
|
|
4
|
+
esbuild: true
|
|
5
|
+
'@parcel/watcher': true
|
|
6
|
+
'@nativescript/core': false
|
|
7
|
+
catalogs:
|
|
8
|
+
xplat:
|
|
9
|
+
"@nativescript-community/octane": 0.2.5
|
|
10
|
+
"@nativescript/core": 9.1.3
|
|
11
|
+
"@nativescript/types": 9.1.4
|
|
12
|
+
"@octane-xplat/cli": 0.16.0
|
|
13
|
+
"@octane-xplat/jsx": 0.16.0
|
|
14
|
+
"@octane-xplat/ui": 0.16.0
|
|
15
|
+
"@octanejs/vite-plugin": 0.1.61
|
|
16
|
+
"@tsrx/oxc": 0.20.0
|
|
17
|
+
"@tsrx/typescript-plugin": 0.4.11
|
|
18
|
+
octane: 0.11.0
|
|
19
|
+
tsrx-typegen: 0.2.2
|
|
20
|
+
typescript: 5.9.3
|
|
21
|
+
vite: 8.3.0
|
|
22
|
+
vitest: 4.1.11
|
|
23
|
+
overrides:
|
|
24
|
+
"@nativescript/vite>esbuild": 0.27.7
|
|
25
|
+
"@nativescript-community/vite-octane>esbuild": 0.27.7
|
|
26
|
+
vite>esbuild: 0.27.7
|
|
27
|
+
configDependencies:
|
|
28
|
+
"@octane-xplat/patches": 0.16.0
|
|
29
|
+
allowUnusedPatches: true
|
|
30
|
+
# Framework patches are supplied by the @octane-xplat/patches config dependency and
|
|
31
|
+
# applied via pnpm patchedDependencies. Managed upstream by @octane-xplat/cli (`xplat
|
|
32
|
+
# patches apply` refreshes, `xplat patches check` verifies); do not edit by hand.
|
|
33
|
+
patchedDependencies:
|
|
34
|
+
# Published 0.11.0 still ships none of the retained fixes: it adds the document guard
|
|
35
|
+
# context around installDefaultSignalOwner and reflows the compile.js hook-classification
|
|
36
|
+
# sites, but every patched feature remains absent upstream. Retains renderer-owned
|
|
37
|
+
# Children.toArray/map with explicit universal-native re-exports for older runtimes,
|
|
38
|
+
# universal signal-read tracking and local hooks, root event-error forwarding, the
|
|
39
|
+
# complete universal imperative-ref lifecycle, the Descriptor declaring-owner reader
|
|
40
|
+
# fallback, and the signal-owner/enclosingOwner chain so child reads reuse instance
|
|
41
|
+
# declarations. Verified against the registry 0.11.0 tarball; all hunks re-anchored to the
|
|
42
|
+
# rewritten compile.js and document-owner call sites. Disposes DOM provider descendants
|
|
43
|
+
# when children become null or undefined, releasing their refs and effects.
|
|
44
|
+
octane@0.11.0: node_modules/.pnpm-config/@octane-xplat/patches/patches/octane@0.11.0.patch
|
|
45
|
+
# Published 9.1.3 ships the #11446 nested-tab-frame lifecycle fix and iOS explicit-size
|
|
46
|
+
# flex alignment, so those hunks are removed. Retains the unshipped parent-padding
|
|
47
|
+
# measure-spec fix and Android explicit-size flex alignment, iOS continuous corner
|
|
48
|
+
# clipping, CSS @layer cascade support, custom Android variable-font weight mapping, and
|
|
49
|
+
# percentage translate parsing, native view, and animation support. Verified against the
|
|
50
|
+
# registry 9.1.3 tarball; it has no Windows implementation, so the separate Windows
|
|
51
|
+
# preview patch remains.
|
|
52
|
+
"@nativescript/core@9.1.3": node_modules/.pnpm-config/@octane-xplat/patches/patches/@nativescript__core@9.1.3.patch
|
|
53
|
+
# @nativescript/vite serializes bundled CSS and dev app.css through reworkcss `css`@3.0.0,
|
|
54
|
+
# which mis-parses @layer into garbage selectors — rules die before reaching
|
|
55
|
+
# _populateRules. Adds atlayer() covering block and statement forms. Applies to a
|
|
56
|
+
# transitive dep — no app declares it directly.
|
|
57
|
+
css@3.0.0: node_modules/.pnpm-config/@octane-xplat/patches/patches/css@3.0.0.patch
|
|
58
|
+
# Dev-server fixes still missing after @nativescript/vite 8.0.17 added percent decoding
|
|
59
|
+
# for path-style /ns/m and Vue /ns/sfc requests (NativeScript#11483): collect re-export
|
|
60
|
+
# specifiers in the .vite/deps rewrite, route /@fs paths outside both roots through /ns/m
|
|
61
|
+
# (linked checkouts bypass the device transform upstream), and probe the non-active
|
|
62
|
+
# platform + `native` suffix tags in module candidates. The deps-bundle esbuild passes
|
|
63
|
+
# ignore vite resolve.alias, so a dep importing bare `octane` bundles the DOM runtime
|
|
64
|
+
# beside the universal one (hooks crash on boot, octane-xplat#3) — an onResolve plugin
|
|
65
|
+
# redirects `octane` → `octane/universal/native`. tsconfig-paths and the generated
|
|
66
|
+
# build-time checker moduleSuffixes also need the `.mobile` tier for iOS/Android/visionOS
|
|
67
|
+
# so `.mobile` leaves resolve under mapped imports and `ns build`. Served `/node_modules/`
|
|
68
|
+
# tails now also scan pnpm's `.pnpm` store and `link:`/`file:`/`portal:` dep roots — a
|
|
69
|
+
# linked package's transitive deps (e.g. @iconify/utils under @octane-xplat/icons) resolve
|
|
70
|
+
# nowhere else and 404 the dev session. findMonorepoWorkspaceRoot no longer treats a lone
|
|
71
|
+
# turbo.json as a workspace root — Turborepo's per-package task configs marked apps/* as
|
|
72
|
+
# roots, masking the real pnpm root so served `/node_modules/` tails never reached the
|
|
73
|
+
# `.pnpm` store scan and non-hoisted transitive deps like source-map-js 404'd dev boot.
|
|
74
|
+
# Linked dependency fallbacks also discover each linked package's enclosing workspace and
|
|
75
|
+
# reuse the cached, bounded workspace node_modules scan so transitive workspace siblings
|
|
76
|
+
# (auth to secure-storage to a private native plugin) resolve without the consumer
|
|
77
|
+
# supplying that workspace root. Transform candidates now keep root-relative URLs only
|
|
78
|
+
# when they identify the discovered file; nested linked-dependency and pnpm-store matches
|
|
79
|
+
# inside the app root use their actual filesystem paths, preserving query suffixes. The
|
|
80
|
+
# /ns/m import rewriter now resolves `#`-prefixed package `imports` specifiers through the
|
|
81
|
+
# importer's own package.json — raw-read node_modules files (e.g. octane's
|
|
82
|
+
# dist/signals/graph.js importing `#octane/dist/signal-actions/graph`) otherwise reach the
|
|
83
|
+
# device verbatim and the HTTP loader throws `Cannot find module`, deadlocking dev boot
|
|
84
|
+
# before any boot recording can bundle the dep. NativeScript#11551: preserve user virtual
|
|
85
|
+
# stylesheet imports while retaining browser-helper filtering, route virtual CSS through
|
|
86
|
+
# the native inline compiler/registration path before the generic virtual-module shortcut,
|
|
87
|
+
# and relay Vite virtual stylesheet updates as tagged native CSS updates through the same
|
|
88
|
+
# adapted-text endpoint. Empty sheets clear previous rules; CSS compilation failures
|
|
89
|
+
# return HTTP 500 instead of raw CSS.
|
|
90
|
+
"@nativescript/vite@8.0.17": node_modules/.pnpm-config/@octane-xplat/patches/patches/@nativescript__vite@8.0.17.patch
|
|
91
|
+
# Retains the workspace's NativeScript driver fixes when upgrading to 0.2.5 for portal
|
|
92
|
+
# support: a prop dropped from an update's complete prop bag — or set to
|
|
93
|
+
# `undefined`/`null` — is a removal that restores the documented default
|
|
94
|
+
# (Property/CssProperty setters get `unsetValue`, plain fields the captured pre-prop
|
|
95
|
+
# value, `style` keys diff per key); a never-applied `undefined` still skips the write.
|
|
96
|
+
# Also advertises the implemented visibility capability, carries Octane callback ref
|
|
97
|
+
# types, and preserves authored Grid row/col/span metadata. Hosts custom-layout containers
|
|
98
|
+
# (e.g. MasonKit ViewBase) that own child lists via
|
|
99
|
+
# insertChild/removeChild/getChildrenCount without subclassing LayoutBase. Additionally,
|
|
100
|
+
# the masonry cutover: masonview resolves to MasonKit View and scrollview to MasonKit
|
|
101
|
+
# Scroll as the only layout containers, with zero layout props — every former prop name
|
|
102
|
+
# warns-and-drops and all CSS semantics arrive through the style bag; style keys on a
|
|
103
|
+
# mason child route to its leaf (stashed pre-attach, replayed at attach) via
|
|
104
|
+
# Style.fromView.
|
|
105
|
+
"@nativescript-community/octane@0.2.5": node_modules/.pnpm-config/@octane-xplat/patches/patches/@nativescript-community__octane@0.2.5.patch
|
|
106
|
+
# octaneServerStrategy's SCRIPT_FILE_RE only covers [jt]sx? — .tsrx edits never emit the
|
|
107
|
+
# deferred ns:hmr-delta broadcast, so component HMR silently never reaches the device.
|
|
108
|
+
# Also counts open /ns-hmr sockets so the update summary stops reporting recipients=0 for
|
|
109
|
+
# delivered updates.
|
|
110
|
+
"@nativescript-community/vite-octane@0.2.1": node_modules/.pnpm-config/@octane-xplat/patches/patches/@nativescript-community__vite-octane@0.2.1.patch
|
|
111
|
+
# Enables `resolveHiddenExtensions` on the language plugin's typescript facet so
|
|
112
|
+
# extensionless specifiers (e.g. './Text') probe `.tsrx` after moduleSuffixes — required
|
|
113
|
+
# for a single extensionless shared barrel to resolve per-platform leaves under tsrx-tsc
|
|
114
|
+
# and the IDE plugin.
|
|
115
|
+
"@tsrx/typescript-plugin@0.4.11": node_modules/.pnpm-config/@octane-xplat/patches/patches/@tsrx__typescript-plugin@0.4.11.patch
|
|
116
|
+
# linkifyjs declares /\p{L}/u and /\p{Emoji}/u as regex literals at module scope;
|
|
117
|
+
# NativeScript's embedded V8 builds without ICU, so the literals throw SyntaxError at
|
|
118
|
+
# parse time and poison the whole bundle (any bundled app importing @tiptap/extension-link
|
|
119
|
+
# dies on boot). Rewrites them as try/catch new RegExp builds with ASCII-range fallbacks —
|
|
120
|
+
# same behavior where ICU exists, graceful degradation where it doesn't.
|
|
121
|
+
linkifyjs@4.3.3: node_modules/.pnpm-config/@octane-xplat/patches/patches/linkifyjs@4.3.3.patch
|
|
122
|
+
# useEditor.ts reads bare process.env.NODE_ENV — no node global exists in the harness
|
|
123
|
+
# typecheck program. Adds a module-local process declaration for typecheck. (The
|
|
124
|
+
# './Context' self-import half of the 0.0.51 patch shipped upstream in 0.0.52 via
|
|
125
|
+
# octanejs/octane#1502.)
|
|
126
|
+
"@octanejs/tiptap@0.0.52": node_modules/.pnpm-config/@octane-xplat/patches/patches/@octanejs__tiptap@0.0.52.patch
|
|
127
|
+
# @lexical/link declares a /\p{L}\p{N}/u URL matcher as a regex literal at module scope;
|
|
128
|
+
# NativeScript's embedded V8 builds without ICU, so the literal throws SyntaxError at
|
|
129
|
+
# parse time and poisons the whole bundle (any bundled app importing @lexical/link dies on
|
|
130
|
+
# boot). Same fix as linkifyjs: try/catch new RegExp with an ASCII-range fallback — the
|
|
131
|
+
# matcher only feeds autolink, which native doesn't use.
|
|
132
|
+
"@lexical/link@0.51.0": node_modules/.pnpm-config/@octane-xplat/patches/patches/@lexical__link@0.51.0.patch
|
|
133
|
+
# ui-image 5.x regressed two iOS prefetch behaviors the 4.x line shipped (still present in
|
|
134
|
+
# 4.6.20): prefetchToCacheType ignores its cacheType argument — SDWebImagePrefetcher's
|
|
135
|
+
# default context stores to disk+memory either way, so a 'disk' prefetch also decodes and
|
|
136
|
+
# warms memory, diverging from Android's bytes-only Glide downloadOnly — and
|
|
137
|
+
# getContextFromOptions drops PrefetchOptions.headers because it never sets
|
|
138
|
+
# SDWebImageContextDownloadRequestModifier, so prefetch({headers}) silently sends no
|
|
139
|
+
# headers on iOS while Android's CustomGlideUrl forwards them. Ports upstream's own 4.x
|
|
140
|
+
# implementation — SDWebImageContextStoreCacheType on the prefetch context plus the
|
|
141
|
+
# request-modifier branch in getContextFromOptions — and additionally sets
|
|
142
|
+
# SDWebImageContextOriginalStoreCacheType so a memory prefetch does not spill original
|
|
143
|
+
# bytes to disk.
|
|
144
|
+
"@nativescript-community/ui-image@5.0.17": node_modules/.pnpm-config/@octane-xplat/patches/patches/@nativescript-community__ui-image@5.0.17.patch
|
|
145
|
+
# @nativescript/doctor's Android runtime check reads the app's raw devDependencies
|
|
146
|
+
# specifier and npm dist-tag resolves anything that isn't a semver range — a pnpm
|
|
147
|
+
# `catalog:` pin throws 'The determined Android runtime version ... is not valid' and
|
|
148
|
+
# kills `ns build android` before toolchain checks. Resolve catalog specifiers through the
|
|
149
|
+
# installed package's manifest, reusing the existing tgz-branch mechanism.
|
|
150
|
+
"@nativescript/doctor@2.0.18": node_modules/.pnpm-config/@octane-xplat/patches/patches/@nativescript__doctor@2.0.18.patch
|
|
151
|
+
# list/index.ios.js assigns `ObjCProtocols = [MasonListDelegate]` at module scope.
|
|
152
|
+
# MasonListDelegate is declared in Mason-Swift.h, which the app's metadata generation does
|
|
153
|
+
# not surface as a runtime global — importing masonkit on iOS throws `MasonListDelegate is
|
|
154
|
+
# not defined` during bundle eval and kills the app at boot. Guard the binding; actual
|
|
155
|
+
# List delegate conformance when the protocol is absent is a separate gap.
|
|
156
|
+
"@triniwiz/nativescript-masonkit@1.0.0-beta.110": node_modules/.pnpm-config/@octane-xplat/patches/patches/@triniwiz__nativescript-masonkit@1.0.0-beta.110.patch
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** @jsxImportSource @octane-xplat/jsx */
|
|
2
|
+
import { Text, View } from '@octane-xplat/ui'
|
|
3
|
+
import { normalizeBadgeLabel } from './normalizeBadgeLabel'
|
|
4
|
+
import type { BadgeProps } from './props'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Render a short label using Octane's NativeScript elements.
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { Badge } from 'octane-xplat-library'
|
|
11
|
+
*
|
|
12
|
+
* <Badge label="Ready" />
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function Badge(props: BadgeProps) {
|
|
16
|
+
return (
|
|
17
|
+
<View className={props.className}>
|
|
18
|
+
<Text>{normalizeBadgeLabel(props.label)}</Text>
|
|
19
|
+
</View>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/** @jsxImportSource @octane-xplat/jsx/dom */
|
|
2
|
+
import { Text, View } from '@octane-xplat/ui'
|
|
3
|
+
import { normalizeBadgeLabel } from './normalizeBadgeLabel'
|
|
4
|
+
import type { BadgeProps } from './props'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Render a short label using Octane's web elements.
|
|
8
|
+
* @example
|
|
9
|
+
* ```tsx
|
|
10
|
+
* import { Badge } from 'octane-xplat-library'
|
|
11
|
+
*
|
|
12
|
+
* <Badge label="Ready" />
|
|
13
|
+
* ```
|
|
14
|
+
*/
|
|
15
|
+
export function Badge(props: BadgeProps) {
|
|
16
|
+
return (
|
|
17
|
+
<View className={props.className}>
|
|
18
|
+
<Text>{normalizeBadgeLabel(props.label)}</Text>
|
|
19
|
+
</View>
|
|
20
|
+
)
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Trim surrounding whitespace from a badge label.
|
|
3
|
+
* @example
|
|
4
|
+
* ```ts
|
|
5
|
+
* import { normalizeBadgeLabel } from 'octane-xplat-library'
|
|
6
|
+
*
|
|
7
|
+
* normalizeBadgeLabel(' Ready ')
|
|
8
|
+
* ```
|
|
9
|
+
*/
|
|
10
|
+
export function normalizeBadgeLabel(label: string): string {
|
|
11
|
+
return label.trim()
|
|
12
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/** Props for the starter badge component. */
|
|
2
|
+
export interface BadgeProps {
|
|
3
|
+
/** Text displayed inside the badge.
|
|
4
|
+
* @example
|
|
5
|
+
* ```tsx
|
|
6
|
+
* import { Badge } from 'octane-xplat-library'
|
|
7
|
+
*
|
|
8
|
+
* <Badge label="Ready" />
|
|
9
|
+
* ```
|
|
10
|
+
*/
|
|
11
|
+
label: string
|
|
12
|
+
/** Optional class name forwarded to the outer view. */
|
|
13
|
+
className?: string
|
|
14
|
+
}
|
|
@@ -0,0 +1,156 @@
|
|
|
1
|
+
import assert from 'node:assert/strict'
|
|
2
|
+
import { spawnSync } from 'node:child_process'
|
|
3
|
+
import {
|
|
4
|
+
cpSync,
|
|
5
|
+
mkdirSync,
|
|
6
|
+
mkdtempSync,
|
|
7
|
+
readdirSync,
|
|
8
|
+
readFileSync,
|
|
9
|
+
rmSync,
|
|
10
|
+
symlinkSync,
|
|
11
|
+
writeFileSync,
|
|
12
|
+
} from 'node:fs'
|
|
13
|
+
|
|
14
|
+
import { tmpdir } from 'node:os'
|
|
15
|
+
import { dirname, join, resolve } from 'node:path'
|
|
16
|
+
import { fileURLToPath } from 'node:url'
|
|
17
|
+
|
|
18
|
+
const packageRoot = resolve(dirname(fileURLToPath(import.meta.url)), '..')
|
|
19
|
+
const sourceManifest = JSON.parse(readFileSync(join(packageRoot, 'package.json'), 'utf8'))
|
|
20
|
+
const temporary = mkdtempSync(join(tmpdir(), 'octane-library-consumer-'))
|
|
21
|
+
|
|
22
|
+
function run(command, args, cwd) {
|
|
23
|
+
const result = spawnSync(command, args, { cwd, encoding: 'utf8', maxBuffer: 16 * 1024 * 1024 })
|
|
24
|
+
if (result.stdout) {
|
|
25
|
+
process.stdout.write(result.stdout)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
if (result.stderr) {
|
|
29
|
+
process.stderr.write(result.stderr)
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
if (result.error) {
|
|
33
|
+
throw result.error
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
assert.equal(result.status, 0, `${command} ${args.join(' ')} failed`)
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function installDirectory(root, name, destination) {
|
|
40
|
+
const segments = name.split('/')
|
|
41
|
+
const path = join(destination, 'node_modules', ...segments)
|
|
42
|
+
mkdirSync(dirname(path), { recursive: true })
|
|
43
|
+
cpSync(root, path, { recursive: true })
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
try {
|
|
47
|
+
const pack = join(temporary, 'pack')
|
|
48
|
+
const extracted = join(temporary, 'extracted')
|
|
49
|
+
mkdirSync(pack)
|
|
50
|
+
mkdirSync(extracted)
|
|
51
|
+
run('pnpm', ['pack', '--pack-destination', pack], packageRoot)
|
|
52
|
+
const tarball = readdirSync(pack).find((name) => name.endsWith('.tgz'))
|
|
53
|
+
assert.ok(tarball)
|
|
54
|
+
run('tar', ['-xzf', join(pack, tarball), '-C', extracted], temporary)
|
|
55
|
+
const packed = join(extracted, 'package')
|
|
56
|
+
const manifest = JSON.parse(readFileSync(join(packed, 'package.json'), 'utf8'))
|
|
57
|
+
assert.ok(manifest.exports['.'].web.default.startsWith('./src/'))
|
|
58
|
+
assert.ok(manifest.exports['.'].native.default.startsWith('./src/'))
|
|
59
|
+
assert.ok(manifest.exports['.'].web.types)
|
|
60
|
+
assert.ok(manifest.exports['.'].native.types)
|
|
61
|
+
|
|
62
|
+
for (const target of ['web', 'native']) {
|
|
63
|
+
for (const mode of ['bundler', 'nodenext']) {
|
|
64
|
+
const consumer = join(temporary, `${target}-${mode}`)
|
|
65
|
+
mkdirSync(consumer)
|
|
66
|
+
mkdirSync(join(consumer, 'node_modules'), { recursive: true })
|
|
67
|
+
installDirectory(packed, sourceManifest.name, consumer)
|
|
68
|
+
for (const dependency of [
|
|
69
|
+
'octane',
|
|
70
|
+
'@octane-xplat/jsx',
|
|
71
|
+
'@octane-xplat/ui',
|
|
72
|
+
...(target === 'native'
|
|
73
|
+
? ['@nativescript-community/octane', '@nativescript/core', '@nativescript/types']
|
|
74
|
+
: []),
|
|
75
|
+
]) {
|
|
76
|
+
const source = join(packageRoot, 'node_modules', ...dependency.split('/'))
|
|
77
|
+
const destination = join(consumer, 'node_modules', ...dependency.split('/'))
|
|
78
|
+
mkdirSync(dirname(destination), { recursive: true })
|
|
79
|
+
symlinkSync(source, destination, 'dir')
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
writeFileSync(join(consumer, 'package.json'), '{"type":"module"}')
|
|
83
|
+
writeFileSync(
|
|
84
|
+
join(consumer, 'consumer.tsx'),
|
|
85
|
+
`import { Badge, type BadgeProps } from '${sourceManifest.name}'
|
|
86
|
+
const props: BadgeProps = { label: 'Ready' }
|
|
87
|
+
const element = <Badge {...props} />
|
|
88
|
+
// @ts-expect-error label is required
|
|
89
|
+
const missing = <Badge />
|
|
90
|
+
// @ts-expect-error label must be a string
|
|
91
|
+
const invalid = <Badge label={1} />
|
|
92
|
+
void element; void missing; void invalid
|
|
93
|
+
`,
|
|
94
|
+
)
|
|
95
|
+
|
|
96
|
+
writeFileSync(
|
|
97
|
+
join(consumer, 'tsconfig.json'),
|
|
98
|
+
JSON.stringify(
|
|
99
|
+
{
|
|
100
|
+
compilerOptions: {
|
|
101
|
+
strict: true,
|
|
102
|
+
noEmit: true,
|
|
103
|
+
skipLibCheck: true,
|
|
104
|
+
target: 'esnext',
|
|
105
|
+
types: [],
|
|
106
|
+
module: mode === 'bundler' ? 'esnext' : 'nodenext',
|
|
107
|
+
moduleResolution: mode,
|
|
108
|
+
jsx: 'react-jsx',
|
|
109
|
+
jsxImportSource: target === 'native' ? '@octane-xplat/jsx' : '@octane-xplat/jsx/dom',
|
|
110
|
+
customConditions: [target],
|
|
111
|
+
moduleSuffixes: target === 'web' ? ['.web', ''] : ['.mobile', ''],
|
|
112
|
+
},
|
|
113
|
+
files: ['consumer.tsx'],
|
|
114
|
+
},
|
|
115
|
+
null,
|
|
116
|
+
'\t',
|
|
117
|
+
),
|
|
118
|
+
)
|
|
119
|
+
|
|
120
|
+
run(
|
|
121
|
+
process.execPath,
|
|
122
|
+
[join(packageRoot, 'node_modules/typescript/bin/tsc'), '-p', 'tsconfig.json'],
|
|
123
|
+
consumer,
|
|
124
|
+
)
|
|
125
|
+
|
|
126
|
+
const listed = spawnSync(
|
|
127
|
+
process.execPath,
|
|
128
|
+
[
|
|
129
|
+
join(packageRoot, 'node_modules/typescript/bin/tsc'),
|
|
130
|
+
'-p',
|
|
131
|
+
'tsconfig.json',
|
|
132
|
+
'--listFilesOnly',
|
|
133
|
+
],
|
|
134
|
+
{ cwd: consumer, encoding: 'utf8' },
|
|
135
|
+
)
|
|
136
|
+
|
|
137
|
+
assert.equal(listed.status, 0, listed.stderr)
|
|
138
|
+
const implementation = listed.stdout
|
|
139
|
+
.split('\n')
|
|
140
|
+
.filter(
|
|
141
|
+
(file) =>
|
|
142
|
+
file.includes(`/node_modules/${sourceManifest.name}/src/`) && !file.endsWith('.d.ts'),
|
|
143
|
+
)
|
|
144
|
+
|
|
145
|
+
assert.deepEqual(
|
|
146
|
+
implementation,
|
|
147
|
+
[],
|
|
148
|
+
'consumer types use declarations without package implementation',
|
|
149
|
+
)
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
console.log('packed consumer: web/native declarations pass Bundler and NodeNext')
|
|
154
|
+
} finally {
|
|
155
|
+
rmSync(temporary, { recursive: true, force: true })
|
|
156
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "./tsconfig.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"jsxImportSource": "@octane-xplat/jsx"
|
|
5
|
+
},
|
|
6
|
+
"environments": {
|
|
7
|
+
"web": {
|
|
8
|
+
"include": ["src/**/*.{ts,tsx,tsrx}"]
|
|
9
|
+
},
|
|
10
|
+
"native": {
|
|
11
|
+
"include": ["src/**/*.{ts,tsx,tsrx}"],
|
|
12
|
+
"compilerOptions": {
|
|
13
|
+
"types": ["@nativescript/types"]
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
{
|
|
2
|
+
"compilerOptions": {
|
|
3
|
+
"strict": true,
|
|
4
|
+
"target": "es2022",
|
|
5
|
+
"module": "esnext",
|
|
6
|
+
"moduleResolution": "bundler",
|
|
7
|
+
"jsx": "react-jsx",
|
|
8
|
+
"jsxImportSource": "@octane-xplat/jsx",
|
|
9
|
+
"moduleSuffixes": [
|
|
10
|
+
"",
|
|
11
|
+
".web",
|
|
12
|
+
".ios",
|
|
13
|
+
".android",
|
|
14
|
+
".mobile",
|
|
15
|
+
".native",
|
|
16
|
+
".macos",
|
|
17
|
+
".linux",
|
|
18
|
+
".windows"
|
|
19
|
+
],
|
|
20
|
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
21
|
+
"types": ["@nativescript/types"],
|
|
22
|
+
"noEmit": true,
|
|
23
|
+
"skipLibCheck": true
|
|
24
|
+
},
|
|
25
|
+
"include": ["src/**/*.ts", "src/**/*.tsx", "src/**/*.tsrx"],
|
|
26
|
+
"exclude": ["dist", "types", "node_modules"]
|
|
27
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"targets": {
|
|
3
|
+
"octane": {
|
|
4
|
+
"renderer": "@octane-xplat/jsx",
|
|
5
|
+
"project": "tsconfig.types.json",
|
|
6
|
+
"outDir": "types",
|
|
7
|
+
"entrypoints": {
|
|
8
|
+
".": {
|
|
9
|
+
"source": "src/index.ts",
|
|
10
|
+
"runtime": ["./src/index.ts", "./src/index.web.ts"],
|
|
11
|
+
"types": ["./types/index.d.ts", "./types/index.web.d.ts"]
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|