@ossy/app 1.21.4 → 1.22.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/cli/build.task.js CHANGED
@@ -54,14 +54,21 @@ function ensureDir (dir) {
54
54
  // folders (e.g. `apps/home.page.jsx` and `analytics/home.page.jsx`) from
55
55
  // colliding on the Rollup input map — which the filesystem already
56
56
  // guarantees can't happen at the relative-path level.
57
- function entryNameFromSource (sourcePath, srcDir) {
57
+ //
58
+ // For installed-package entries, `packageName` is provided and used as a
59
+ // prefix so that e.g. `@ossy/authentication/sign-in.page.jsx` becomes
60
+ // `ossy__authentication__sign-in.page` and never collides with a local file.
61
+ function entryNameFromSource (sourcePath, srcDir, packageName) {
58
62
  const rel = path.relative(srcDir, sourcePath).replace(/\\/g, '/')
59
- return rel.replace(/\//g, '__').replace(/\.(jsx?|tsx?|mjs|cjs)$/, '')
63
+ const flat = rel.replace(/\//g, '__').replace(/\.(jsx?|tsx?|mjs|cjs)$/, '')
64
+ if (!packageName) return flat
65
+ const pkgPrefix = packageName.replace(/^@/, '').replace(/\//g, '__').replace(/[^a-zA-Z0-9_-]/g, '_')
66
+ return `${pkgPrefix}__${flat}`
60
67
  }
61
68
 
62
- function stubFileNameFor (kind, sourcePath, srcDir) {
69
+ function stubFileNameFor (kind, sourcePath, srcDir, packageName) {
63
70
  const ext = kind === 'page' ? '.entry.jsx' : '.entry.js'
64
- return entryNameFromSource(sourcePath, srcDir) + ext
71
+ return entryNameFromSource(sourcePath, srcDir, packageName) + ext
65
72
  }
66
73
 
67
74
  function relImport (fromAbs, toAbs) {
@@ -176,12 +183,13 @@ export async function build (cliArgs = []) {
176
183
  const stubInputMap = {}
177
184
 
178
185
  for (const entry of allEntries) {
179
- const { kind, sourcePath } = entry
180
- const inputName = entryNameFromSource(sourcePath, srcDir)
181
- const stubAbs = path.join(stubDir, stubFileNameFor(kind, sourcePath, srcDir))
186
+ const { kind, sourcePath, packageName, packageSrcDir } = entry
187
+ const effectiveSrcDir = packageSrcDir || srcDir
188
+ const inputName = entryNameFromSource(sourcePath, effectiveSrcDir, packageName)
189
+ const stubAbs = path.join(stubDir, stubFileNameFor(kind, sourcePath, effectiveSrcDir, packageName))
182
190
  fs.writeFileSync(stubAbs, stubFor(kind, { stubAbs, sourceAbs: sourcePath }), 'utf8')
183
191
  stubInputMap[inputName] = stubAbs
184
- entriesByStub.set(stubAbs, { kind, sourcePath })
192
+ entriesByStub.set(stubAbs, { kind, sourcePath, packageName, packageSrcDir })
185
193
  }
186
194
 
187
195
  const configPath = path.resolve(srcDir, 'config.js')
@@ -10,8 +10,10 @@ export const RESOURCE_FILE_PATTERN = /\.resource\.(mjs|cjs|js)$/
10
10
  * @typedef {'page' | 'api' | 'task' | 'resource'} EntryKind
11
11
  *
12
12
  * @typedef {object} PlatformEntry
13
- * @property {EntryKind} kind Which bucket this entry lives in.
14
- * @property {string} sourcePath Absolute path to the user-authored source file.
13
+ * @property {EntryKind} kind Which bucket this entry lives in.
14
+ * @property {string} sourcePath Absolute path to the user-authored source file.
15
+ * @property {string} [packageName] npm package name, set only for installed-package entries.
16
+ * @property {string} [packageSrcDir] Absolute path to the package's `src/` dir, set only for installed-package entries.
15
17
  *
16
18
  * @typedef {object} PlatformFiles
17
19
  * @property {PlatformEntry[]} pages Discovered `*.page.{jsx,tsx,...}` entries.
@@ -76,11 +78,72 @@ export function filePathToRoute (absPath, srcDir) {
76
78
  return { id, path: defaultPageRoute(id) }
77
79
  }
78
80
 
81
+ /**
82
+ * Walks `node_modules/` in `projectRoot` looking for packages that declare an
83
+ * `"ossy": { "src": "./src" }` field in their `package.json`. Returns entries
84
+ * from those packages' source trees, tagged with `packageName` and
85
+ * `packageSrcDir` so the build pipeline can namespace them correctly.
86
+ *
87
+ * Handles both flat packages (`node_modules/foo`) and scoped packages
88
+ * (`node_modules/@scope/foo`).
89
+ *
90
+ * @param {string} projectRoot Absolute path to the consuming project root (parent of `src/`).
91
+ * @returns {PlatformEntry[]}
92
+ */
93
+ export function discoverInstalledPackageEntries (projectRoot) {
94
+ const nmDir = path.join(projectRoot, 'node_modules')
95
+ if (!fs.existsSync(nmDir) || !fs.statSync(nmDir).isDirectory()) return []
96
+
97
+ const entries = []
98
+
99
+ const tryPackageDir = (pkgDir) => {
100
+ const pkgJsonPath = path.join(pkgDir, 'package.json')
101
+ if (!fs.existsSync(pkgJsonPath)) return
102
+ let pkg
103
+ try { pkg = JSON.parse(fs.readFileSync(pkgJsonPath, 'utf8')) } catch { return }
104
+ if (!pkg.ossy?.src) return
105
+
106
+ const packageSrcDir = path.resolve(pkgDir, pkg.ossy.src)
107
+ const files = [
108
+ ...discoverFilesByPattern(packageSrcDir, PAGE_FILE_PATTERN),
109
+ ...discoverFilesByPattern(packageSrcDir, API_FILE_PATTERN),
110
+ ...discoverFilesByPattern(packageSrcDir, TASK_FILE_PATTERN),
111
+ ...discoverFilesByPattern(packageSrcDir, RESOURCE_FILE_PATTERN),
112
+ ]
113
+ for (const sourcePath of files) {
114
+ const stat = fs.statSync(sourcePath)
115
+ if (!stat.isFile() || stat.size === 0) continue
116
+ const kind = classifyFile(sourcePath)
117
+ if (!kind) continue
118
+ entries.push({ kind, sourcePath, packageName: pkg.name, packageSrcDir })
119
+ }
120
+ }
121
+
122
+ for (const entry of fs.readdirSync(nmDir, { withFileTypes: true })) {
123
+ if (!entry.isDirectory() && !entry.isSymbolicLink()) continue
124
+ if (entry.name.startsWith('@')) {
125
+ const scopeDir = path.join(nmDir, entry.name)
126
+ for (const scoped of fs.readdirSync(scopeDir, { withFileTypes: true })) {
127
+ if (scoped.isDirectory() || scoped.isSymbolicLink()) {
128
+ tryPackageDir(path.join(scopeDir, scoped.name))
129
+ }
130
+ }
131
+ } else {
132
+ tryPackageDir(path.join(nmDir, entry.name))
133
+ }
134
+ }
135
+
136
+ return entries
137
+ }
138
+
79
139
  /**
80
140
  * Walks `srcDir` and returns the user-authored entries the platform cares
81
141
  * about, bucketed by kind. Empty (zero-byte) source files are skipped — we
82
142
  * treat them as placeholders the user is mid-creating.
83
143
  *
144
+ * Also scans installed npm packages that declare an `"ossy": { "src" }` field
145
+ * in their `package.json`, merging their entries into the same output buckets.
146
+ *
84
147
  * Metadata isn't read here on purpose: the build pipeline reads it from the
85
148
  * bundled output instead, which lets users compute `metadata.path` (and
86
149
  * anything else) from imports, config, env vars, etc.
@@ -90,19 +153,27 @@ export function filePathToRoute (absPath, srcDir) {
90
153
  */
91
154
  export default async function getPlatformFiles (srcDir) {
92
155
  const out = { pages: [], apis: [], tasks: [], resources: [] }
93
- const all = [
156
+ const bucketByKind = { page: 'pages', api: 'apis', task: 'tasks', resource: 'resources' }
157
+
158
+ const localFiles = [
94
159
  ...discoverFilesByPattern(srcDir, PAGE_FILE_PATTERN),
95
160
  ...discoverFilesByPattern(srcDir, API_FILE_PATTERN),
96
161
  ...discoverFilesByPattern(srcDir, TASK_FILE_PATTERN),
97
162
  ...discoverFilesByPattern(srcDir, RESOURCE_FILE_PATTERN),
98
163
  ]
99
- const bucketByKind = { page: 'pages', api: 'apis', task: 'tasks', resource: 'resources' }
100
- for (const sourcePath of all) {
164
+ for (const sourcePath of localFiles) {
101
165
  const stat = fs.statSync(sourcePath)
102
166
  if (!stat.isFile() || stat.size === 0) continue
103
167
  const kind = classifyFile(sourcePath)
104
168
  if (!kind) continue
105
169
  out[bucketByKind[kind]].push({ kind, sourcePath })
106
170
  }
171
+
172
+ const projectRoot = path.dirname(srcDir)
173
+ const packageEntries = discoverInstalledPackageEntries(projectRoot)
174
+ for (const entry of packageEntries) {
175
+ out[bucketByKind[entry.kind]].push(entry)
176
+ }
177
+
107
178
  return out
108
179
  }
@@ -138,7 +138,7 @@ export function manifestPlugin ({ entriesByStub, srcDir, staticOutDir, configVal
138
138
  }
139
139
 
140
140
  const rawMeta = (mod && mod.metadata) || {}
141
- const id = rawMeta.id || metadataIdFromFile(entryInfo.sourcePath, srcDir)
141
+ const id = rawMeta.id || metadataIdFromFile(entryInfo.sourcePath, entryInfo.packageSrcDir || srcDir)
142
142
  if (!id) {
143
143
  this.error(`[@ossy/app][build] ${entryInfo.kind} entry missing metadata.id: ${entryInfo.sourcePath}`)
144
144
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ossy/app",
3
- "version": "1.21.4",
3
+ "version": "1.22.1",
4
4
  "description": "",
5
5
  "source": "./src/index.js",
6
6
  "main": "./src/index.js",
@@ -25,7 +25,7 @@
25
25
  "devDependencies": {
26
26
  "@jest/globals": "^30.2.0",
27
27
  "jest": "^30.2.0",
28
- "typescript": "^5.9.3"
28
+ "typescript": "^6.0.3"
29
29
  },
30
30
  "dependencies": {
31
31
  "@babel/cli": "^7.26.4",
@@ -33,17 +33,17 @@
33
33
  "@babel/eslint-parser": "^7.15.8",
34
34
  "@babel/preset-react": "^7.26.3",
35
35
  "@babel/register": "^7.25.9",
36
- "@ossy/connected-components": "^1.21.4",
37
- "@ossy/design-system": "^1.21.4",
38
- "@ossy/pages": "^1.21.4",
39
- "@ossy/platform": "^1.20.4",
40
- "@ossy/router": "^1.21.4",
41
- "@ossy/router-react": "^1.21.4",
42
- "@ossy/sdk": "^1.21.4",
43
- "@ossy/sdk-react": "^1.21.4",
44
- "@ossy/themes": "^1.21.4",
36
+ "@ossy/connected-components": "^1.22.1",
37
+ "@ossy/design-system": "^1.22.1",
38
+ "@ossy/pages": "^1.22.1",
39
+ "@ossy/platform": "^1.21.1",
40
+ "@ossy/router": "^1.22.1",
41
+ "@ossy/router-react": "^1.22.1",
42
+ "@ossy/sdk": "^1.22.1",
43
+ "@ossy/sdk-react": "^1.22.1",
44
+ "@ossy/themes": "^1.22.1",
45
45
  "@rollup/plugin-alias": "^6.0.0",
46
- "@rollup/plugin-babel": "6.1.0",
46
+ "@rollup/plugin-babel": "^7.0.0",
47
47
  "@rollup/plugin-commonjs": "^29.0.0",
48
48
  "@rollup/plugin-inject": "^5.0.5",
49
49
  "@rollup/plugin-json": "^6.1.0",
@@ -61,7 +61,7 @@
61
61
  "rollup-plugin-copy": "^3.5.0",
62
62
  "rollup-plugin-delete": "^3.0.2",
63
63
  "rollup-plugin-dts": "^6.1.0",
64
- "rollup-plugin-node-externals": "^8.1.2",
64
+ "rollup-plugin-node-externals": "^9.0.1",
65
65
  "rollup-plugin-peer-deps-external": "^2.2.4",
66
66
  "rollup-plugin-postcss-modules": "^2.1.1",
67
67
  "rollup-plugin-preserve-directives": "^0.4.0",
@@ -75,5 +75,5 @@
75
75
  "README.md",
76
76
  "tsconfig.json"
77
77
  ],
78
- "gitHead": "296ec9d1c354589c223e533b230535d2b4e6db84"
78
+ "gitHead": "8e757fb891965b78be752b9c7db72cf45470144d"
79
79
  }