create-qpq-app 0.1.5 → 0.1.6

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.
@@ -8,17 +8,120 @@ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, ge
8
8
  step((generator = generator.apply(thisArg, _arguments || [])).next());
9
9
  });
10
10
  };
11
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
11
14
  Object.defineProperty(exports, "__esModule", { value: true });
12
15
  exports.transpileToJavaScript = void 0;
16
+ const fs_1 = __importDefault(require("fs"));
17
+ const path_1 = __importDefault(require("path"));
18
+ const files_1 = require("../lib/files");
13
19
  const types_1 = require("../types");
14
- // Placeholder for the JavaScript flavour a later pass will transpile the
15
- // scaffolded TypeScript sources here. For now it's an honest no-op so the
16
- // language answer already threads through the pipeline.
20
+ // Convert the scaffolded TypeScript app to JavaScript: per-file type
21
+ // stripping (JSX preserved, comments kept), then remove the TypeScript
22
+ // build plumbing the app no longer needs.
23
+ //
24
+ // The qpq toolchain runs the result as-is: the CLI's ts-node require hook
25
+ // compiles the app's ESM-syntax .js at load time (allowJs, added below), and
26
+ // rspack bundles .js/.jsx natively.
17
27
  exports.transpileToJavaScript = {
18
28
  name: 'Converting to JavaScript',
19
29
  shouldRun: (answers) => answers.language === types_1.AppLanguage.javascript,
20
- run: () => __awaiter(void 0, void 0, void 0, function* () {
21
- console.log(' JavaScript output is not available yet — generating TypeScript for now.');
30
+ run: (_a) => __awaiter(void 0, [_a], void 0, function* ({ targetDirectory }) {
31
+ var _b, _c, _d;
32
+ // Lazy so TypeScript scaffolds never load the compiler.
33
+ /* eslint-disable @typescript-eslint/no-require-imports */
34
+ const ts = require('typescript');
35
+ const prettier = require('prettier');
36
+ /* eslint-enable @typescript-eslint/no-require-imports */
37
+ // The transpiler re-prints files in its own style; format the output with
38
+ // the app's own prettier settings so generated code matches the repo.
39
+ const prettierRcPath = path_1.default.join(targetDirectory, '.prettierrc');
40
+ const prettierOptions = fs_1.default.existsSync(prettierRcPath) ? (0, files_1.readJsonFile)(prettierRcPath) : {};
41
+ const compilerOptions = {
42
+ target: ts.ScriptTarget.ESNext,
43
+ module: ts.ModuleKind.ESNext, // keep import/export statements as written
44
+ jsx: ts.JsxEmit.Preserve,
45
+ removeComments: false,
46
+ };
47
+ let converted = 0;
48
+ for (const filePath of (0, files_1.listFilesRecursive)(targetDirectory)) {
49
+ if (filePath.endsWith('.d.ts')) {
50
+ fs_1.default.rmSync(filePath);
51
+ continue;
52
+ }
53
+ const isTsx = filePath.endsWith('.tsx');
54
+ if (!isTsx && !filePath.endsWith('.ts')) {
55
+ continue;
56
+ }
57
+ const source = fs_1.default.readFileSync(filePath, 'utf8');
58
+ const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });
59
+ // Type-only statements leave blank gaps behind — collapse runs of them.
60
+ const collapsed = outputText.replace(/\n{3,}/g, '\n\n');
61
+ const outputPath = filePath.replace(/\.tsx?$/, isTsx ? '.jsx' : '.js');
62
+ const output = yield prettier.format(collapsed, Object.assign(Object.assign({}, prettierOptions), { filepath: outputPath }));
63
+ fs_1.default.writeFileSync(outputPath, output);
64
+ fs_1.default.rmSync(filePath);
65
+ converted += 1;
66
+ }
67
+ // TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the
68
+ // per-package tsc scripts all go. Lib packages no longer build — their
69
+ // package.json main points straight at src.
70
+ let libsRepointed = 0;
71
+ for (const filePath of (0, files_1.listFilesRecursive)(targetDirectory)) {
72
+ const baseName = path_1.default.basename(filePath);
73
+ if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path_1.default.join(targetDirectory, 'tsconfig.json')) {
74
+ fs_1.default.rmSync(filePath);
75
+ continue;
76
+ }
77
+ if (baseName === 'package.json' && filePath !== path_1.default.join(targetDirectory, 'package.json')) {
78
+ const packageJson = (0, files_1.readJsonFile)(filePath);
79
+ let changed = false;
80
+ if ((_b = packageJson.scripts) === null || _b === void 0 ? void 0 : _b['validate-ts']) {
81
+ delete packageJson.scripts['validate-ts'];
82
+ changed = true;
83
+ }
84
+ // Lib packages (identified by their tsc build) get served from
85
+ // source. A tsc build with an unexpected main means the template's
86
+ // conventions moved — fail loudly rather than scaffold a broken app.
87
+ if (((_c = packageJson.scripts) === null || _c === void 0 ? void 0 : _c.build) === 'tsc -b') {
88
+ if (packageJson.main !== './dist/src/index.js') {
89
+ throw new Error(`${filePath} has a tsc build but main is "${packageJson.main}" (expected "./dist/src/index.js") — update transpileToJavaScript for the new template convention.`);
90
+ }
91
+ packageJson.main = './src/index.js';
92
+ delete packageJson.typings;
93
+ delete packageJson.scripts.build;
94
+ packageJson.exports = { '.': { default: './src/index.js' } };
95
+ packageJson.files = ['src'];
96
+ changed = true;
97
+ libsRepointed += 1;
98
+ }
99
+ if (changed) {
100
+ (0, files_1.writeJsonFile)(filePath, packageJson);
101
+ }
102
+ }
103
+ }
104
+ if (converted === 0 || libsRepointed === 0) {
105
+ throw new Error(`JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`);
106
+ }
107
+ // The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads
108
+ // its ts-node block, and allowJs makes that hook compile the app's
109
+ // ESM-syntax .js files (imports, __dirname) at load time.
110
+ fs_1.default.rmSync(path_1.default.join(targetDirectory, 'types'), { recursive: true, force: true });
111
+ fs_1.default.rmSync(path_1.default.join(targetDirectory, 'tsconfig.base.json'), { force: true });
112
+ const rootTsconfigPath = path_1.default.join(targetDirectory, 'tsconfig.json');
113
+ const rootTsconfig = (0, files_1.readJsonFile)(rootTsconfigPath);
114
+ rootTsconfig['ts-node'].compilerOptions.allowJs = true;
115
+ // Scope the hook to this repo — allowJs must never recompile quidproquo
116
+ // libs living outside node_modules (file:-linked dev setups).
117
+ rootTsconfig['ts-node'].scope = true;
118
+ rootTsconfig['ts-node'].scopeDir = '.';
119
+ (0, files_1.writeJsonFile)(rootTsconfigPath, rootTsconfig);
120
+ const rootPackageJsonPath = path_1.default.join(targetDirectory, 'package.json');
121
+ const rootPackageJson = (0, files_1.readJsonFile)(rootPackageJsonPath);
122
+ (_d = rootPackageJson.scripts) === null || _d === void 0 ? true : delete _d['validate-ts'];
123
+ (0, files_1.writeJsonFile)(rootPackageJsonPath, rootPackageJson);
124
+ console.log(` Converted ${converted} files to JavaScript.`);
22
125
  }),
23
126
  };
24
127
  //# sourceMappingURL=008_transpileToJavaScript.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":";;;;;;;;;;;;AAAA,oCAAyD;AAEzD,2EAA2E;AAC3E,0EAA0E;AAC1E,wDAAwD;AAC3C,QAAA,qBAAqB,GAAqB;IACrD,IAAI,EAAE,0BAA0B;IAEhC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,mBAAW,CAAC,UAAU;IAEnE,GAAG,EAAE,GAAS,EAAE;QACd,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC,CAAA;CACF,CAAC","sourcesContent":["import { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Placeholder for the JavaScript flavour — a later pass will transpile the\n// scaffolded TypeScript sources here. For now it's an honest no-op so the\n// language answer already threads through the pipeline.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async () => {\n console.log(' JavaScript output is not available yet — generating TypeScript for now.');\n },\n};\n"]}
1
+ {"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { listFilesRecursive, readJsonFile, writeJsonFile } from '../lib/files';\nimport { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Convert the scaffolded TypeScript app to JavaScript: per-file type\n// stripping (JSX preserved, comments kept), then remove the TypeScript\n// build plumbing the app no longer needs.\n//\n// The qpq toolchain runs the result as-is: the CLI's ts-node require hook\n// compiles the app's ESM-syntax .js at load time (allowJs, added below), and\n// rspack bundles .js/.jsx natively.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async ({ targetDirectory }) => {\n // Lazy so TypeScript scaffolds never load the compiler.\n /* eslint-disable @typescript-eslint/no-require-imports */\n const ts = require('typescript') as typeof import('typescript');\n const prettier = require('prettier') as typeof import('prettier');\n /* eslint-enable @typescript-eslint/no-require-imports */\n\n // The transpiler re-prints files in its own style; format the output with\n // the app's own prettier settings so generated code matches the repo.\n const prettierRcPath = path.join(targetDirectory, '.prettierrc');\n const prettierOptions = fs.existsSync(prettierRcPath) ? readJsonFile(prettierRcPath) : {};\n\n const compilerOptions: import('typescript').CompilerOptions = {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext, // keep import/export statements as written\n jsx: ts.JsxEmit.Preserve,\n removeComments: false,\n };\n\n let converted = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n if (filePath.endsWith('.d.ts')) {\n fs.rmSync(filePath);\n continue;\n }\n\n const isTsx = filePath.endsWith('.tsx');\n if (!isTsx && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const source = fs.readFileSync(filePath, 'utf8');\n const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });\n\n // Type-only statements leave blank gaps behind — collapse runs of them.\n const collapsed = outputText.replace(/\\n{3,}/g, '\\n\\n');\n\n const outputPath = filePath.replace(/\\.tsx?$/, isTsx ? '.jsx' : '.js');\n const output = await prettier.format(collapsed, { ...prettierOptions, filepath: outputPath });\n\n fs.writeFileSync(outputPath, output);\n fs.rmSync(filePath);\n converted += 1;\n }\n\n // TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the\n // per-package tsc scripts all go. Lib packages no longer build — their\n // package.json main points straight at src.\n let libsRepointed = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n const baseName = path.basename(filePath);\n\n if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path.join(targetDirectory, 'tsconfig.json')) {\n fs.rmSync(filePath);\n continue;\n }\n\n if (baseName === 'package.json' && filePath !== path.join(targetDirectory, 'package.json')) {\n const packageJson = readJsonFile(filePath);\n let changed = false;\n\n if (packageJson.scripts?.['validate-ts']) {\n delete packageJson.scripts['validate-ts'];\n changed = true;\n }\n\n // Lib packages (identified by their tsc build) get served from\n // source. A tsc build with an unexpected main means the template's\n // conventions moved — fail loudly rather than scaffold a broken app.\n if (packageJson.scripts?.build === 'tsc -b') {\n if (packageJson.main !== './dist/src/index.js') {\n throw new Error(\n `${filePath} has a tsc build but main is \"${packageJson.main}\" (expected \"./dist/src/index.js\") — update transpileToJavaScript for the new template convention.`,\n );\n }\n\n packageJson.main = './src/index.js';\n delete packageJson.typings;\n delete packageJson.scripts.build;\n packageJson.exports = { '.': { default: './src/index.js' } };\n packageJson.files = ['src'];\n changed = true;\n libsRepointed += 1;\n }\n\n if (changed) {\n writeJsonFile(filePath, packageJson);\n }\n }\n }\n\n if (converted === 0 || libsRepointed === 0) {\n throw new Error(\n `JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`,\n );\n }\n\n // The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads\n // its ts-node block, and allowJs makes that hook compile the app's\n // ESM-syntax .js files (imports, __dirname) at load time.\n fs.rmSync(path.join(targetDirectory, 'types'), { recursive: true, force: true });\n fs.rmSync(path.join(targetDirectory, 'tsconfig.base.json'), { force: true });\n\n const rootTsconfigPath = path.join(targetDirectory, 'tsconfig.json');\n const rootTsconfig = readJsonFile(rootTsconfigPath);\n rootTsconfig['ts-node'].compilerOptions.allowJs = true;\n // Scope the hook to this repo — allowJs must never recompile quidproquo\n // libs living outside node_modules (file:-linked dev setups).\n rootTsconfig['ts-node'].scope = true;\n rootTsconfig['ts-node'].scopeDir = '.';\n writeJsonFile(rootTsconfigPath, rootTsconfig);\n\n const rootPackageJsonPath = path.join(targetDirectory, 'package.json');\n const rootPackageJson = readJsonFile(rootPackageJsonPath);\n delete rootPackageJson.scripts?.['validate-ts'];\n writeJsonFile(rootPackageJsonPath, rootPackageJson);\n\n console.log(` Converted ${converted} files to JavaScript.`);\n },\n};\n"]}
@@ -1,12 +1,111 @@
1
+ import fs from 'fs';
2
+ import path from 'path';
3
+ import { listFilesRecursive, readJsonFile, writeJsonFile } from '../lib/files';
1
4
  import { AppLanguage } from '../types';
2
- // Placeholder for the JavaScript flavour a later pass will transpile the
3
- // scaffolded TypeScript sources here. For now it's an honest no-op so the
4
- // language answer already threads through the pipeline.
5
+ // Convert the scaffolded TypeScript app to JavaScript: per-file type
6
+ // stripping (JSX preserved, comments kept), then remove the TypeScript
7
+ // build plumbing the app no longer needs.
8
+ //
9
+ // The qpq toolchain runs the result as-is: the CLI's ts-node require hook
10
+ // compiles the app's ESM-syntax .js at load time (allowJs, added below), and
11
+ // rspack bundles .js/.jsx natively.
5
12
  export const transpileToJavaScript = {
6
13
  name: 'Converting to JavaScript',
7
14
  shouldRun: (answers) => answers.language === AppLanguage.javascript,
8
- run: async () => {
9
- console.log(' JavaScript output is not available yet generating TypeScript for now.');
15
+ run: async ({ targetDirectory }) => {
16
+ // Lazy so TypeScript scaffolds never load the compiler.
17
+ /* eslint-disable @typescript-eslint/no-require-imports */
18
+ const ts = require('typescript');
19
+ const prettier = require('prettier');
20
+ /* eslint-enable @typescript-eslint/no-require-imports */
21
+ // The transpiler re-prints files in its own style; format the output with
22
+ // the app's own prettier settings so generated code matches the repo.
23
+ const prettierRcPath = path.join(targetDirectory, '.prettierrc');
24
+ const prettierOptions = fs.existsSync(prettierRcPath) ? readJsonFile(prettierRcPath) : {};
25
+ const compilerOptions = {
26
+ target: ts.ScriptTarget.ESNext,
27
+ module: ts.ModuleKind.ESNext, // keep import/export statements as written
28
+ jsx: ts.JsxEmit.Preserve,
29
+ removeComments: false,
30
+ };
31
+ let converted = 0;
32
+ for (const filePath of listFilesRecursive(targetDirectory)) {
33
+ if (filePath.endsWith('.d.ts')) {
34
+ fs.rmSync(filePath);
35
+ continue;
36
+ }
37
+ const isTsx = filePath.endsWith('.tsx');
38
+ if (!isTsx && !filePath.endsWith('.ts')) {
39
+ continue;
40
+ }
41
+ const source = fs.readFileSync(filePath, 'utf8');
42
+ const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });
43
+ // Type-only statements leave blank gaps behind — collapse runs of them.
44
+ const collapsed = outputText.replace(/\n{3,}/g, '\n\n');
45
+ const outputPath = filePath.replace(/\.tsx?$/, isTsx ? '.jsx' : '.js');
46
+ const output = await prettier.format(collapsed, { ...prettierOptions, filepath: outputPath });
47
+ fs.writeFileSync(outputPath, output);
48
+ fs.rmSync(filePath);
49
+ converted += 1;
50
+ }
51
+ // TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the
52
+ // per-package tsc scripts all go. Lib packages no longer build — their
53
+ // package.json main points straight at src.
54
+ let libsRepointed = 0;
55
+ for (const filePath of listFilesRecursive(targetDirectory)) {
56
+ const baseName = path.basename(filePath);
57
+ if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path.join(targetDirectory, 'tsconfig.json')) {
58
+ fs.rmSync(filePath);
59
+ continue;
60
+ }
61
+ if (baseName === 'package.json' && filePath !== path.join(targetDirectory, 'package.json')) {
62
+ const packageJson = readJsonFile(filePath);
63
+ let changed = false;
64
+ if (packageJson.scripts?.['validate-ts']) {
65
+ delete packageJson.scripts['validate-ts'];
66
+ changed = true;
67
+ }
68
+ // Lib packages (identified by their tsc build) get served from
69
+ // source. A tsc build with an unexpected main means the template's
70
+ // conventions moved — fail loudly rather than scaffold a broken app.
71
+ if (packageJson.scripts?.build === 'tsc -b') {
72
+ if (packageJson.main !== './dist/src/index.js') {
73
+ throw new Error(`${filePath} has a tsc build but main is "${packageJson.main}" (expected "./dist/src/index.js") — update transpileToJavaScript for the new template convention.`);
74
+ }
75
+ packageJson.main = './src/index.js';
76
+ delete packageJson.typings;
77
+ delete packageJson.scripts.build;
78
+ packageJson.exports = { '.': { default: './src/index.js' } };
79
+ packageJson.files = ['src'];
80
+ changed = true;
81
+ libsRepointed += 1;
82
+ }
83
+ if (changed) {
84
+ writeJsonFile(filePath, packageJson);
85
+ }
86
+ }
87
+ }
88
+ if (converted === 0 || libsRepointed === 0) {
89
+ throw new Error(`JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`);
90
+ }
91
+ // The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads
92
+ // its ts-node block, and allowJs makes that hook compile the app's
93
+ // ESM-syntax .js files (imports, __dirname) at load time.
94
+ fs.rmSync(path.join(targetDirectory, 'types'), { recursive: true, force: true });
95
+ fs.rmSync(path.join(targetDirectory, 'tsconfig.base.json'), { force: true });
96
+ const rootTsconfigPath = path.join(targetDirectory, 'tsconfig.json');
97
+ const rootTsconfig = readJsonFile(rootTsconfigPath);
98
+ rootTsconfig['ts-node'].compilerOptions.allowJs = true;
99
+ // Scope the hook to this repo — allowJs must never recompile quidproquo
100
+ // libs living outside node_modules (file:-linked dev setups).
101
+ rootTsconfig['ts-node'].scope = true;
102
+ rootTsconfig['ts-node'].scopeDir = '.';
103
+ writeJsonFile(rootTsconfigPath, rootTsconfig);
104
+ const rootPackageJsonPath = path.join(targetDirectory, 'package.json');
105
+ const rootPackageJson = readJsonFile(rootPackageJsonPath);
106
+ delete rootPackageJson.scripts?.['validate-ts'];
107
+ writeJsonFile(rootPackageJsonPath, rootPackageJson);
108
+ console.log(` Converted ${converted} files to JavaScript.`);
10
109
  },
11
110
  };
12
111
  //# sourceMappingURL=008_transpileToJavaScript.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAoB,MAAM,UAAU,CAAC;AAEzD,2EAA2E;AAC3E,0EAA0E;AAC1E,wDAAwD;AACxD,MAAM,CAAC,MAAM,qBAAqB,GAAqB;IACrD,IAAI,EAAE,0BAA0B;IAEhC,SAAS,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,OAAO,CAAC,QAAQ,KAAK,WAAW,CAAC,UAAU;IAEnE,GAAG,EAAE,KAAK,IAAI,EAAE;QACd,OAAO,CAAC,GAAG,CAAC,2EAA2E,CAAC,CAAC;IAC3F,CAAC;CACF,CAAC","sourcesContent":["import { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Placeholder for the JavaScript flavour — a later pass will transpile the\n// scaffolded TypeScript sources here. For now it's an honest no-op so the\n// language answer already threads through the pipeline.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async () => {\n console.log(' JavaScript output is not available yet — generating TypeScript for now.');\n },\n};\n"]}
1
+ {"version":3,"file":"008_transpileToJavaScript.js","sourceRoot":"","sources":["../../../src/steps/008_transpileToJavaScript.ts"],"names":[],"mappings":"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","sourcesContent":["import fs from 'fs';\nimport path from 'path';\n\nimport { listFilesRecursive, readJsonFile, writeJsonFile } from '../lib/files';\nimport { AppLanguage, CreateQpqAppStep } from '../types';\n\n// Convert the scaffolded TypeScript app to JavaScript: per-file type\n// stripping (JSX preserved, comments kept), then remove the TypeScript\n// build plumbing the app no longer needs.\n//\n// The qpq toolchain runs the result as-is: the CLI's ts-node require hook\n// compiles the app's ESM-syntax .js at load time (allowJs, added below), and\n// rspack bundles .js/.jsx natively.\nexport const transpileToJavaScript: CreateQpqAppStep = {\n name: 'Converting to JavaScript',\n\n shouldRun: (answers) => answers.language === AppLanguage.javascript,\n\n run: async ({ targetDirectory }) => {\n // Lazy so TypeScript scaffolds never load the compiler.\n /* eslint-disable @typescript-eslint/no-require-imports */\n const ts = require('typescript') as typeof import('typescript');\n const prettier = require('prettier') as typeof import('prettier');\n /* eslint-enable @typescript-eslint/no-require-imports */\n\n // The transpiler re-prints files in its own style; format the output with\n // the app's own prettier settings so generated code matches the repo.\n const prettierRcPath = path.join(targetDirectory, '.prettierrc');\n const prettierOptions = fs.existsSync(prettierRcPath) ? readJsonFile(prettierRcPath) : {};\n\n const compilerOptions: import('typescript').CompilerOptions = {\n target: ts.ScriptTarget.ESNext,\n module: ts.ModuleKind.ESNext, // keep import/export statements as written\n jsx: ts.JsxEmit.Preserve,\n removeComments: false,\n };\n\n let converted = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n if (filePath.endsWith('.d.ts')) {\n fs.rmSync(filePath);\n continue;\n }\n\n const isTsx = filePath.endsWith('.tsx');\n if (!isTsx && !filePath.endsWith('.ts')) {\n continue;\n }\n\n const source = fs.readFileSync(filePath, 'utf8');\n const { outputText } = ts.transpileModule(source, { compilerOptions, fileName: filePath });\n\n // Type-only statements leave blank gaps behind — collapse runs of them.\n const collapsed = outputText.replace(/\\n{3,}/g, '\\n\\n');\n\n const outputPath = filePath.replace(/\\.tsx?$/, isTsx ? '.jsx' : '.js');\n const output = await prettier.format(collapsed, { ...prettierOptions, filepath: outputPath });\n\n fs.writeFileSync(outputPath, output);\n fs.rmSync(filePath);\n converted += 1;\n }\n\n // TypeScript build plumbing: tsconfigs, the ambient types/ dir, and the\n // per-package tsc scripts all go. Lib packages no longer build — their\n // package.json main points straight at src.\n let libsRepointed = 0;\n for (const filePath of listFilesRecursive(targetDirectory)) {\n const baseName = path.basename(filePath);\n\n if (baseName.startsWith('tsconfig') && baseName.endsWith('.json') && filePath !== path.join(targetDirectory, 'tsconfig.json')) {\n fs.rmSync(filePath);\n continue;\n }\n\n if (baseName === 'package.json' && filePath !== path.join(targetDirectory, 'package.json')) {\n const packageJson = readJsonFile(filePath);\n let changed = false;\n\n if (packageJson.scripts?.['validate-ts']) {\n delete packageJson.scripts['validate-ts'];\n changed = true;\n }\n\n // Lib packages (identified by their tsc build) get served from\n // source. A tsc build with an unexpected main means the template's\n // conventions moved — fail loudly rather than scaffold a broken app.\n if (packageJson.scripts?.build === 'tsc -b') {\n if (packageJson.main !== './dist/src/index.js') {\n throw new Error(\n `${filePath} has a tsc build but main is \"${packageJson.main}\" (expected \"./dist/src/index.js\") — update transpileToJavaScript for the new template convention.`,\n );\n }\n\n packageJson.main = './src/index.js';\n delete packageJson.typings;\n delete packageJson.scripts.build;\n packageJson.exports = { '.': { default: './src/index.js' } };\n packageJson.files = ['src'];\n changed = true;\n libsRepointed += 1;\n }\n\n if (changed) {\n writeJsonFile(filePath, packageJson);\n }\n }\n }\n\n if (converted === 0 || libsRepointed === 0) {\n throw new Error(\n `JavaScript conversion looks wrong: ${converted} files transpiled, ${libsRepointed} lib packages repointed — has the template changed shape?`,\n );\n }\n\n // The ROOT tsconfig.json stays — the qpq CLI's ts-node require hook reads\n // its ts-node block, and allowJs makes that hook compile the app's\n // ESM-syntax .js files (imports, __dirname) at load time.\n fs.rmSync(path.join(targetDirectory, 'types'), { recursive: true, force: true });\n fs.rmSync(path.join(targetDirectory, 'tsconfig.base.json'), { force: true });\n\n const rootTsconfigPath = path.join(targetDirectory, 'tsconfig.json');\n const rootTsconfig = readJsonFile(rootTsconfigPath);\n rootTsconfig['ts-node'].compilerOptions.allowJs = true;\n // Scope the hook to this repo — allowJs must never recompile quidproquo\n // libs living outside node_modules (file:-linked dev setups).\n rootTsconfig['ts-node'].scope = true;\n rootTsconfig['ts-node'].scopeDir = '.';\n writeJsonFile(rootTsconfigPath, rootTsconfig);\n\n const rootPackageJsonPath = path.join(targetDirectory, 'package.json');\n const rootPackageJson = readJsonFile(rootPackageJsonPath);\n delete rootPackageJson.scripts?.['validate-ts'];\n writeJsonFile(rootPackageJsonPath, rootPackageJson);\n\n console.log(` Converted ${converted} files to JavaScript.`);\n },\n};\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-qpq-app",
3
- "version": "0.1.5",
3
+ "version": "0.1.6",
4
4
  "description": "Scaffold a new quidproquo app — npx create-qpq-app my-app",
5
5
  "main": "./lib/commonjs/index.js",
6
6
  "module": "./lib/esm/index.js",
@@ -22,6 +22,7 @@
22
22
  "build:esm": "tsc -p tsconfig.esm.json",
23
23
  "build:bin-perms": "node -e \"require('fs').chmodSync('lib/commonjs/bin/createQpqApp.js', 0o755)\"",
24
24
  "snapshot-template": "node ./scripts/snapshotTemplate.mjs",
25
+ "smoke-test": "node ./scripts/smokeTest.mjs",
25
26
  "prepack": "npm run snapshot-template",
26
27
  "lint": "npx eslint .",
27
28
  "lint:fix": "npx eslint . --fix",
@@ -44,12 +45,13 @@
44
45
  },
45
46
  "homepage": "https://github.com/joe-coady/quidproquo#readme",
46
47
  "dependencies": {
47
- "@inquirer/prompts": "^8.5.2"
48
+ "@inquirer/prompts": "^8.5.2",
49
+ "prettier": "^3.2.5",
50
+ "typescript": "^5.8.2"
48
51
  },
49
52
  "devDependencies": {
50
53
  "@types/node": "^22.13.13",
51
- "quidproquo-tsconfig": "0.1.5",
52
- "typescript": "^5.8.2"
54
+ "quidproquo-tsconfig": "0.1.6"
53
55
  },
54
56
  "bin": {
55
57
  "create-qpq-app": "./lib/commonjs/bin/createQpqApp.js"
@@ -30,6 +30,20 @@ import {
30
30
 
31
31
  const modulePrefix = 'todo';
32
32
 
33
+ // The deployed version tag — git sha when available, so a fresh checkout
34
+ // (or a scaffold that skipped git init) still loads.
35
+ const getVersionTag = (): string => {
36
+ try {
37
+ return execSync('git rev-parse --short HEAD', {
38
+ stdio: ['ignore', 'pipe', 'ignore'],
39
+ })
40
+ .toString()
41
+ .trim();
42
+ } catch {
43
+ return 'no-git';
44
+ }
45
+ };
46
+
33
47
  // The shared config every todo service starts from — app identity, dns,
34
48
  // auth, admin, api and caching. Each service's infrastructure.ts layers its
35
49
  // own resources on top of this.
@@ -50,11 +64,7 @@ export const defineTodoService = (
50
64
  process.env.ACTOR_NAME
51
65
  ),
52
66
 
53
- defineApplicationVersion(
54
- `${execSync('git rev-parse --short HEAD')
55
- .toString()
56
- .trim()}-${new Date().toISOString()}`
57
- ),
67
+ defineApplicationVersion(`${getVersionTag()}-${new Date().toISOString()}`),
58
68
 
59
69
  defineDns(domainName),
60
70
 
@@ -4,6 +4,10 @@
4
4
  "compilerOptions": {
5
5
  "jsx": "react-jsx",
6
6
  "module": "commonjs",
7
+ // This repo is the create-qpq-app template; its JavaScript flavour is
8
+ // produced by per-file transpilation, which only supports
9
+ // isolatedModules-compatible TypeScript. Keep this on.
10
+ "isolatedModules": true,
7
11
  "rootDir": ".",
8
12
  "declaration": false,
9
13
  "emitDecoratorMetadata": true,