@open-mercato/shared 0.6.7-develop.6785.1.1dd7cfac55 → 0.6.7-develop.6788.1.c2a1520a30

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/build.mjs CHANGED
@@ -2,6 +2,7 @@ import { readFileSync } from 'node:fs'
2
2
  import { dirname, join } from 'node:path'
3
3
  import { fileURLToPath } from 'node:url'
4
4
  import { buildPackage } from '../../scripts/build-package.mjs'
5
+ import { buildVersionSource } from './scripts/versionSource.cjs'
5
6
 
6
7
  const packageDir = dirname(fileURLToPath(import.meta.url))
7
8
  const packageJson = JSON.parse(readFileSync(join(packageDir, 'package.json'), 'utf-8'))
@@ -12,10 +13,7 @@ const injectVersion = {
12
13
  name: 'inject-version',
13
14
  setup(build) {
14
15
  build.onLoad({ filter: /lib\/version\.ts$/ }, async () => ({
15
- contents: `// Build-time generated version
16
- export const APP_VERSION = '${packageVersion}'
17
- export const appVersion = APP_VERSION
18
- `,
16
+ contents: buildVersionSource(packageVersion),
19
17
  loader: 'ts',
20
18
  }))
21
19
  },
@@ -1,4 +1,4 @@
1
- const APP_VERSION = "0.6.7-develop.6785.1.1dd7cfac55";
1
+ const APP_VERSION = "0.6.7-develop.6788.1.c2a1520a30";
2
2
  const appVersion = APP_VERSION;
3
3
  export {
4
4
  APP_VERSION,
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
3
  "sources": ["../../src/lib/version.ts"],
4
- "sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.7-develop.6785.1.1dd7cfac55'\nexport const appVersion = APP_VERSION\n"],
4
+ "sourcesContent": ["// Build-time generated version\nexport const APP_VERSION = '0.6.7-develop.6788.1.c2a1520a30';\nexport const appVersion = APP_VERSION;\n"],
5
5
  "mappings": "AACO,MAAM,cAAc;AACpB,MAAM,aAAa;",
6
6
  "names": []
7
7
  }
package/jest.config.cjs CHANGED
@@ -12,7 +12,8 @@ module.exports = {
12
12
  '^@open-mercato/core/(.*)$': '<rootDir>/../core/src/$1',
13
13
  },
14
14
  transform: {
15
- '^.+\\.(t|j)sx?$': [
15
+ // `.cjs` is included so the build-time source emitters under scripts/ are testable.
16
+ '^.+\\.(cjs|(t|j)sx?)$': [
16
17
  '<rootDir>/../../scripts/jest-mikroorm-transformer.cjs',
17
18
  {
18
19
  tsconfig: {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@open-mercato/shared",
3
- "version": "0.6.7-develop.6785.1.1dd7cfac55",
3
+ "version": "0.6.7-develop.6788.1.c2a1520a30",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -105,7 +105,7 @@
105
105
  "@mikro-orm/core": "^7.1.5",
106
106
  "@mikro-orm/decorators": "^7.1.5",
107
107
  "@mikro-orm/postgresql": "^7.1.5",
108
- "@open-mercato/cache": "0.6.7-develop.6785.1.1dd7cfac55",
108
+ "@open-mercato/cache": "0.6.7-develop.6788.1.c2a1520a30",
109
109
  "@types/sanitize-html": "^2.16.1",
110
110
  "dotenv": "^17.4.2",
111
111
  "pino": "^10.3.1",
@@ -119,6 +119,7 @@
119
119
  "@types/jest": "^30.0.0",
120
120
  "jest": "^30.4.2",
121
121
  "ts-jest": "^29.4.11",
122
+ "ts-morph": "^28.0.0",
122
123
  "typescript": "7.0.2"
123
124
  },
124
125
  "publishConfig": {
@@ -0,0 +1,65 @@
1
+ // Pure source emitter for the build-time replacement of src/lib/version.ts.
2
+ // Kept side-effect free, and CommonJS so both build.mjs and the Jest suite can load it.
3
+
4
+ const { Project, QuoteKind, ScriptKind, StructureKind, VariableDeclarationKind } = require('ts-morph')
5
+
6
+ const VIRTUAL_FILE_NAME = 'version.ts'
7
+ const BANNER = '// Build-time generated version\n'
8
+
9
+ let sharedProject = null
10
+
11
+ function getProject() {
12
+ if (!sharedProject) {
13
+ sharedProject = new Project({
14
+ useInMemoryFileSystem: true,
15
+ manipulationSettings: { quoteKind: QuoteKind.Single },
16
+ })
17
+ }
18
+
19
+ return sharedProject
20
+ }
21
+
22
+ function assertNoSyntacticDiagnostics(project, sourceFile) {
23
+ const diagnostics = project.getProgram().getSyntacticDiagnostics(sourceFile)
24
+ if (diagnostics.length === 0) return
25
+
26
+ const details = diagnostics
27
+ .map((diagnostic) => ` line ${diagnostic.getLineNumber() ?? 0}: ${diagnostic.getMessageText()}`)
28
+ .join('\n')
29
+ throw new Error(`[internal] Generated ${VIRTUAL_FILE_NAME} is not syntactically valid:\n${details}`)
30
+ }
31
+
32
+ function normalizeSourceText(text) {
33
+ const normalized = text.replace(/\r\n/g, '\n')
34
+ return normalized.endsWith('\n') ? normalized : `${normalized}\n`
35
+ }
36
+
37
+ function buildVersionSource(version) {
38
+ const project = getProject()
39
+ const sourceFile = project.createSourceFile(VIRTUAL_FILE_NAME, '', {
40
+ overwrite: true,
41
+ scriptKind: ScriptKind.TS,
42
+ })
43
+
44
+ sourceFile.addVariableStatement({
45
+ kind: StructureKind.VariableStatement,
46
+ isExported: true,
47
+ declarationKind: VariableDeclarationKind.Const,
48
+ declarations: [{ name: 'APP_VERSION', initializer: (writer) => writer.quote(String(version)) }],
49
+ })
50
+
51
+ sourceFile.addVariableStatement({
52
+ kind: StructureKind.VariableStatement,
53
+ isExported: true,
54
+ declarationKind: VariableDeclarationKind.Const,
55
+ declarations: [{ name: 'appVersion', initializer: 'APP_VERSION' }],
56
+ })
57
+
58
+ sourceFile.formatText({ indentSize: 2, convertTabsToSpaces: true })
59
+ sourceFile.insertText(0, BANNER)
60
+ assertNoSyntacticDiagnostics(project, sourceFile)
61
+
62
+ return normalizeSourceText(sourceFile.getFullText())
63
+ }
64
+
65
+ module.exports = { buildVersionSource }
@@ -0,0 +1,46 @@
1
+ import { Project, SyntaxKind } from 'ts-morph'
2
+ import { buildVersionSource } from '../../../scripts/versionSource.cjs'
3
+
4
+ function parse(source: string) {
5
+ const project = new Project({ useInMemoryFileSystem: true })
6
+ const sourceFile = project.createSourceFile('version.ts', source, { overwrite: true })
7
+ return { project, sourceFile }
8
+ }
9
+
10
+ function exportedLiteral(source: string, name: string): string {
11
+ const { sourceFile } = parse(source)
12
+ return sourceFile.getVariableDeclarationOrThrow(name).getInitializerOrThrow().getText()
13
+ }
14
+
15
+ describe('buildVersionSource', () => {
16
+ it('exports both APP_VERSION and appVersion', () => {
17
+ const { sourceFile } = parse(buildVersionSource('1.2.3'))
18
+ expect([...sourceFile.getExportedDeclarations().keys()].sort()).toEqual(['APP_VERSION', 'appVersion'])
19
+ })
20
+
21
+ it('writes the supplied version as the APP_VERSION literal', () => {
22
+ expect(exportedLiteral(buildVersionSource('1.2.3'), 'APP_VERSION')).toBe("'1.2.3'")
23
+ })
24
+
25
+ it('aliases appVersion to APP_VERSION rather than repeating the literal', () => {
26
+ expect(exportedLiteral(buildVersionSource('1.2.3'), 'appVersion')).toBe('APP_VERSION')
27
+ })
28
+
29
+ it('escapes a version string that would otherwise break the literal', () => {
30
+ const source = buildVersionSource("0.0.0-dev'; drop")
31
+ const { sourceFile } = parse(source)
32
+ const literal = sourceFile
33
+ .getVariableDeclarationOrThrow('APP_VERSION')
34
+ .getInitializerIfKindOrThrow(SyntaxKind.StringLiteral)
35
+ expect(literal.getLiteralValue()).toBe("0.0.0-dev'; drop")
36
+ })
37
+
38
+ it('emits zero syntactic diagnostics', () => {
39
+ const { project, sourceFile } = parse(buildVersionSource('1.2.3'))
40
+ expect(project.getProgram().getSyntacticDiagnostics(sourceFile)).toEqual([])
41
+ })
42
+
43
+ it('keeps the build-time banner comment', () => {
44
+ expect(buildVersionSource('1.2.3').startsWith('// Build-time generated version\n')).toBe(true)
45
+ })
46
+ })