From e3bae6d3a963fd77575ed6566d398ea0222ea7d1 Mon Sep 17 00:00:00 2001 From: Theo Steiner Date: Sat, 2 Apr 2022 19:31:03 +0900 Subject: [PATCH 01/10] Set checkJs to false in no-typescript scaffold --- packages/create-svelte/shared/-typescript/jsconfig.json | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/packages/create-svelte/shared/-typescript/jsconfig.json b/packages/create-svelte/shared/-typescript/jsconfig.json index 81ff9770cd8a..e8acf53c104e 100644 --- a/packages/create-svelte/shared/-typescript/jsconfig.json +++ b/packages/create-svelte/shared/-typescript/jsconfig.json @@ -1,3 +1,6 @@ { - "extends": "./.svelte-kit/tsconfig.json" + "extends": "./.svelte-kit/tsconfig.json", + "compilerOptions": { + "checkJs": false + } } From 9160b9da0213bd76a56ea47fb6a3216c9ccd5f88 Mon Sep 17 00:00:00 2001 From: Theo Steiner Date: Tue, 5 Apr 2022 13:11:20 +0900 Subject: [PATCH 02/10] [enhance] add selection for type checking to create-svelte --- packages/create-svelte/bin.js | 18 ++++++++++++------ packages/create-svelte/types/internal.d.ts | 3 ++- 2 files changed, 14 insertions(+), 7 deletions(-) diff --git a/packages/create-svelte/bin.js b/packages/create-svelte/bin.js index 8439db01fc31..3af9c8896c3b 100755 --- a/packages/create-svelte/bin.js +++ b/packages/create-svelte/bin.js @@ -70,12 +70,15 @@ async function main() { }) }, { - type: 'toggle', - name: 'typescript', - message: 'Use TypeScript?', + type: 'select', + name: 'types', + message: 'Add type checking to your project?', initial: false, - active: 'Yes', - inactive: 'No' + choices: [ + { title: 'No', value: false }, + { title: 'TypeScript', value: 'typescript' }, + { title: 'Type checked JavaScript', value: 'checkjs' } + ] }, { type: 'toggle', @@ -116,9 +119,12 @@ async function main() { console.log(bold(green('\nYour project is ready!'))); - if (options.typescript) { + if (options.types === 'typescript') { console.log(bold('✔ Typescript')); console.log(' Inside Svelte components, use diff --git a/packages/create-svelte/templates/default/src/routes/todos/index.ts b/packages/create-svelte/templates/default/src/routes/todos/index.ts index fc8bd4b8efaf..5ca318899587 100644 --- a/packages/create-svelte/templates/default/src/routes/todos/index.ts +++ b/packages/create-svelte/templates/default/src/routes/todos/index.ts @@ -1,6 +1,7 @@ import { api } from './_api'; -import type { RequestHandler } from '@sveltejs/kit'; +import type { RequestHandler } from './index'; +/** @type {import('./index').RequestHandler} */ export const get: RequestHandler = async ({ locals }) => { // locals.userid comes from src/hooks.js const response = await api('get', `todos/${locals.userid}`); @@ -28,6 +29,7 @@ export const get: RequestHandler = async ({ locals }) => { }; }; +/** @type {import('./index').RequestHandler} */ export const post: RequestHandler = async ({ request, locals }) => { const form = await request.formData(); @@ -47,6 +49,7 @@ const redirect = { } }; +/** @type {import('./index').RequestHandler} */ export const patch: RequestHandler = async ({ request, locals }) => { const form = await request.formData(); @@ -58,6 +61,7 @@ export const patch: RequestHandler = async ({ request, locals }) => { return redirect; }; +/** @type {import('./index').RequestHandler} */ export const del: RequestHandler = async ({ request, locals }) => { const form = await request.formData(); From dbe65f0f1f1f450ce820e2050558d07fef756ab5 Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 14 Apr 2022 15:52:40 -0400 Subject: [PATCH 06/10] strip jsdoc from source --- .../create-svelte/scripts/build-templates.js | 154 +++++++++--------- 1 file changed, 80 insertions(+), 74 deletions(-) diff --git a/packages/create-svelte/scripts/build-templates.js b/packages/create-svelte/scripts/build-templates.js index 3367ede9a46d..1acf1e354063 100644 --- a/packages/create-svelte/scripts/build-templates.js +++ b/packages/create-svelte/scripts/build-templates.js @@ -6,9 +6,9 @@ import { transform } from 'sucrase'; import glob from 'tiny-glob/sync.js'; import { mkdirp, rimraf } from '../utils.js'; -/** @param {string} typescript */ -function convert_typescript(typescript) { - const transformed = transform(typescript, { +/** @param {string} content */ +function convert_typescript(content) { + const transformed = transform(content, { transforms: ['typescript'] }); @@ -21,6 +21,11 @@ function convert_typescript(typescript) { }); } +/** @param {string} content */ +function strip_jsdoc(content) { + return content.replace(/\/\*\*[\s\S]+?\*\/[\s\n]+/g, ''); +} + /** @param {Set} shared */ async function generate_templates(shared) { const templates = fs.readdirSync('templates'); @@ -43,6 +48,9 @@ async function generate_templates(shared) { const meta_file = path.join(cwd, '.meta.json'); if (!fs.existsSync(meta_file)) throw new Error('Template must have a .meta.json file'); + /** @type {import('../types/internal.js').File[]} */ + const js = []; + /** @type {import('../types/internal.js').File[]} */ const ts = []; @@ -64,12 +72,76 @@ async function generate_templates(shared) { // ignore contents of .gitignore or .ignore if (!gitignore.accepts(name) || !ignore.accepts(name) || name === '.ignore') return; - if (/\.(js|ts|svelte|svelte\.md)$/.test(name)) { + if (/\.(ts|svelte)$/.test(name)) { const contents = fs.readFileSync(path.join(cwd, name), 'utf8'); - ts.push({ - name, - contents - }); + + if (name.endsWith('.d.ts')) { + if (name.endsWith('app.d.ts')) js.push({ name, contents }); + ts.push({ name, contents }); + } else if (name.endsWith('.ts')) { + ts.push({ + name, + contents: strip_jsdoc(contents) + }); + + js.push({ + name: name.replace(/\.ts$/, '.js'), + contents: convert_typescript(contents) + }); + } else { + // we jump through some hoops, rather than just using svelte.preprocess, + // so that the output preserves the original formatting to the extent + // possible (e.g. preserving double line breaks). Sucrase is the best + // tool for the job because it just removes the types; Prettier then + // tidies up the end result + const js_contents = contents.replace( + /]+)>([\s\S]+?)<\/script>/g, + (m, attrs, typescript) => { + // Sucrase assumes 'unused' imports (which _are_ used, but only + // in the markup) are type imports, and strips them. This step + // prevents it from drawing that conclusion + const imports = []; + const import_pattern = /import (.+?) from/g; + let import_match; + while ((import_match = import_pattern.exec(typescript))) { + const word_pattern = /[a-z_$][a-z0-9_$]*/gi; + let word_match; + while ((word_match = word_pattern.exec(import_match[1]))) { + imports.push(word_match[0]); + } + } + + const suffix = `\n${imports.join(',')}`; + + const transformed = transform(typescript + suffix, { + transforms: ['typescript'] + }).code.slice(0, -suffix.length); + + const contents = prettier + .format(transformed, { + parser: 'babel', + useTabs: true, + singleQuote: true, + trailingComma: 'none', + printWidth: 100 + }) + .trim() + .replace(/^(.)/gm, '\t$1'); + + return `\n${contents}\n`; + } + ); + + js.push({ + name, + contents: js_contents + }); + + ts.push({ + name, + contents: strip_jsdoc(contents) + }); + } } else { const dest = path.join(assets, name.replace(/^\./, 'DOT-')); mkdirp(path.dirname(dest)); @@ -77,72 +149,6 @@ async function generate_templates(shared) { } }); - /** @type {import('../types/internal.js').File[]} */ - const js = []; - - for (const file of ts) { - // The app.d.ts file makes TS/JS aware of some ambient modules, which are - // also needed for JS projects if people turn on "checkJs" in their jsonfig - if (file.name.endsWith('.d.ts')) { - if (file.name.endsWith('app.d.ts')) js.push(file); - } else if (file.name.endsWith('.ts')) { - js.push({ - name: file.name.replace(/\.ts$/, '.js'), - contents: convert_typescript(file.contents) - }); - } else if (file.name.endsWith('.svelte')) { - // we jump through some hoops, rather than just using svelte.preprocess, - // so that the output preserves the original formatting to the extent - // possible (e.g. preserving double line breaks). Sucrase is the best - // tool for the job because it just removes the types; Prettier then - // tidies up the end result - const contents = file.contents.replace( - /]+)>([\s\S]+?)<\/script>/g, - (m, attrs, typescript) => { - // Sucrase assumes 'unused' imports (which _are_ used, but only - // in the markup) are type imports, and strips them. This step - // prevents it from drawing that conclusion - const imports = []; - const import_pattern = /import (.+?) from/g; - let import_match; - while ((import_match = import_pattern.exec(typescript))) { - const word_pattern = /[a-z_$][a-z0-9_$]*/gi; - let word_match; - while ((word_match = word_pattern.exec(import_match[1]))) { - imports.push(word_match[0]); - } - } - - const suffix = `\n${imports.join(',')}`; - - const transformed = transform(typescript + suffix, { - transforms: ['typescript'] - }).code.slice(0, -suffix.length); - - const contents = prettier - .format(transformed, { - parser: 'babel', - useTabs: true, - singleQuote: true, - trailingComma: 'none', - printWidth: 100 - }) - .trim() - .replace(/^(.)/gm, '\t$1'); - - return `\n${contents}\n`; - } - ); - - js.push({ - name: file.name, - contents - }); - } else { - js.push(file); - } - } - fs.copyFileSync(meta_file, `${dir}/meta.json`); fs.writeFileSync(`${dir}/files.ts.json`, JSON.stringify(ts, null, '\t')); fs.writeFileSync(`${dir}/files.js.json`, JSON.stringify(js, null, '\t')); From a9895d83119480909bf7179868b09b77babdb97b Mon Sep 17 00:00:00 2001 From: Rich Harris Date: Thu, 14 Apr 2022 17:39:39 -0400 Subject: [PATCH 07/10] tidy up --- packages/create-svelte/bin.js | 8 ++++---- packages/create-svelte/index.js | 2 +- .../scripts/update-template-repo-contents.js | 2 +- .../shared/+checkjs/package.json | 10 ++++++++++ .../shared/+default+checkjs/package.json | 5 +++++ .../shared/+default+checkjs/svelte.config.js | 20 +++++++++++++++++++ .../shared/-typescript-checkjs/jsconfig.json | 6 ------ .../templates/default/src/lib/form.ts | 3 ++- packages/create-svelte/types/internal.d.ts | 2 +- 9 files changed, 44 insertions(+), 14 deletions(-) create mode 100644 packages/create-svelte/shared/+checkjs/package.json create mode 100644 packages/create-svelte/shared/+default+checkjs/package.json create mode 100644 packages/create-svelte/shared/+default+checkjs/svelte.config.js delete mode 100644 packages/create-svelte/shared/-typescript-checkjs/jsconfig.json diff --git a/packages/create-svelte/bin.js b/packages/create-svelte/bin.js index 3af9c8896c3b..0997c21c274b 100755 --- a/packages/create-svelte/bin.js +++ b/packages/create-svelte/bin.js @@ -72,12 +72,12 @@ async function main() { { type: 'select', name: 'types', - message: 'Add type checking to your project?', + message: 'Add type checking?', initial: false, choices: [ - { title: 'No', value: false }, + { title: 'Type-checked JavaScript', value: 'checkjs' }, { title: 'TypeScript', value: 'typescript' }, - { title: 'Type checked JavaScript', value: 'checkjs' } + { title: 'None', value: null } ] }, { @@ -123,7 +123,7 @@ async function main() { console.log(bold('✔ Typescript')); console.log(' Inside Svelte components, use