{h()}
\n'], + ]; + for (const [name, ...parts] of COMPONENTS) { + const text = parts.join(''); + const want = parts.map((part, i) => (i % 2 === 1 ? part : part.replace(/[^\n]/g, ' '))).join(''); + const got = sfcScriptText(name, text).text; + if (got !== want) { + failures += fail(`sfcScriptText(${name}, ${JSON.stringify(text)}) is ${JSON.stringify(got)}, ` + + `expected ${JSON.stringify(want)}`); + } + } + // ---- 2. source-level: nobody rolls their own. const KNOWN = ['.js', '.jsx', '.mjs', '.cjs', '.flow']; const files: string[] = []; diff --git a/parser/src/utils/javascript/javascript-module-utils.ts b/parser/src/utils/javascript/javascript-module-utils.ts index f301664b2..fad52cfd2 100644 --- a/parser/src/utils/javascript/javascript-module-utils.ts +++ b/parser/src/utils/javascript/javascript-module-utils.ts @@ -1,4 +1,4 @@ -import { JS_SOURCE_EXTENSIONS } from '@/constants/javascript-constants'; +import { JS_COMPONENT_EXTENSIONS, JS_SOURCE_EXTENSIONS } from '@/constants/javascript-constants'; /** * What counts as a platform module, in one place. @@ -129,7 +129,96 @@ export function jsExtensionOf(fileName: string): string { // table, which is the argument for having written one: the function was in use // at eight call sites and every one of them happened to pass a `.js` family // name, so nothing else would ever have shown it. - return (JS_SOURCE_EXTENSIONS as readonly string[]).includes(extension) ? extension : ''; + if ((JS_SOURCE_EXTENSIONS as readonly string[]).includes(extension)) { + return extension; + } + // A component has no `.flow` spelling: `a.vue.flow` is not a declaration file. + return base === name && (JS_COMPONENT_EXTENSIONS as readonly string[]).includes(extension) + ? extension + : ''; +} + +/** Is this a single-file component (`.vue`, `.svelte`, `.astro`), by name? */ +export function isJsComponentFile(fileName: string): boolean { + return (JS_COMPONENT_EXTENSIONS as readonly string[]).includes(jsExtensionOf(fileName)); +} + +/** One ` +{{ childLocal() }} diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/components/Legacy.vue b/graph/test/typescript/cases/81-vue-component-tag/src/components/Legacy.vue new file mode 100644 index 000000000..30c1e158b --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/components/Legacy.vue @@ -0,0 +1,5 @@ + +legacy diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/components/MyWidget.vue b/graph/test/typescript/cases/81-vue-component-tag/src/components/MyWidget.vue new file mode 100644 index 000000000..a705d4550 --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/components/MyWidget.vue @@ -0,0 +1,5 @@ + +{{ widgetLabel() }} diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/components/badge.ts b/graph/test/typescript/cases/81-vue-component-tag/src/components/badge.ts new file mode 100644 index 000000000..7dba71a89 --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/components/badge.ts @@ -0,0 +1 @@ +export function Badge(): string { return 'b'; } diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/components/store.ts b/graph/test/typescript/cases/81-vue-component-tag/src/components/store.ts new file mode 100644 index 000000000..c29d0438b --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/components/store.ts @@ -0,0 +1,2 @@ +function storeInit(): number { return 1; } +export default { value: storeInit() }; diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/main.ts b/graph/test/typescript/cases/81-vue-component-tag/src/main.ts new file mode 100644 index 000000000..5283f2d18 --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/main.ts @@ -0,0 +1,5 @@ +import Parent from './views/Parent.vue'; + +export function mount(): unknown { + return Parent; +} diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/shims-vue.d.ts b/graph/test/typescript/cases/81-vue-component-tag/src/shims-vue.d.ts new file mode 100644 index 000000000..821cca508 --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/shims-vue.d.ts @@ -0,0 +1,4 @@ +declare module '*.vue' { + const component: unknown; + export default component; +} diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/tsconfig.json b/graph/test/typescript/cases/81-vue-component-tag/src/tsconfig.json new file mode 100644 index 000000000..98ff2e003 --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/tsconfig.json @@ -0,0 +1,10 @@ +{ + "compilerOptions": { + "target": "ES2020", + "module": "ESNext", + "moduleResolution": "bundler", + "strict": true, + "noEmit": true + }, + "include": ["**/*.ts", "**/*.vue"] +} diff --git a/graph/test/typescript/cases/81-vue-component-tag/src/views/Parent.vue b/graph/test/typescript/cases/81-vue-component-tag/src/views/Parent.vue new file mode 100644 index 000000000..40e92d4a2 --- /dev/null +++ b/graph/test/typescript/cases/81-vue-component-tag/src/views/Parent.vue @@ -0,0 +1,15 @@ + + +