mirror of
https://github.com/tenrok/vue-meta.git
synced 2026-06-22 09:10:34 +03:00
feat: add deepest resolver (wip)
feat: improve resolver related typing
This commit is contained in:
+16
-1
@@ -22,7 +22,7 @@ app.use(
|
|||||||
)
|
)
|
||||||
|
|
||||||
fs.readdirSync(__dirname)
|
fs.readdirSync(__dirname)
|
||||||
.filter(file => file !== 'ssr')
|
.filter(file => file[0] !== '_' && file !== 'ssr')
|
||||||
.forEach((file) => {
|
.forEach((file) => {
|
||||||
if (fs.statSync(path.join(__dirname, file)).isDirectory()) {
|
if (fs.statSync(path.join(__dirname, file)).isDirectory()) {
|
||||||
app.use(rewrite(`/${file}/*`, `/${file}/index.html`))
|
app.use(rewrite(`/${file}/*`, `/${file}/index.html`))
|
||||||
@@ -32,6 +32,21 @@ fs.readdirSync(__dirname)
|
|||||||
app.use(express.static(path.join(__dirname, '_static')))
|
app.use(express.static(path.join(__dirname, '_static')))
|
||||||
app.use(express.static(__dirname))
|
app.use(express.static(__dirname))
|
||||||
|
|
||||||
|
app.use((req, res, next) => {
|
||||||
|
// Return empty css/javascript files if the file didnt exists
|
||||||
|
// statically. This means we can test/load any js file in
|
||||||
|
// the examples without errors in the browser
|
||||||
|
if (req.url.endsWith('.js')) {
|
||||||
|
res.setHeader('Content-Type', 'application/javascript')
|
||||||
|
res.send('')
|
||||||
|
next()
|
||||||
|
} else if (req.url.endsWith('.css')) {
|
||||||
|
res.setHeader('Content-Type', 'text/css')
|
||||||
|
res.send('')
|
||||||
|
next()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
app.use(async (req, res, next) => {
|
app.use(async (req, res, next) => {
|
||||||
if (!req.url.startsWith('/ssr')) {
|
if (!req.url.startsWith('/ssr')) {
|
||||||
return next()
|
return next()
|
||||||
|
|||||||
@@ -1,9 +1,7 @@
|
|||||||
import {
|
import {
|
||||||
createApp,
|
createApp,
|
||||||
defineComponent,
|
defineComponent,
|
||||||
getCurrentInstance,
|
|
||||||
reactive,
|
reactive,
|
||||||
inject,
|
|
||||||
toRefs,
|
toRefs,
|
||||||
h,
|
h,
|
||||||
watch
|
watch
|
||||||
@@ -20,10 +18,11 @@ const ChildComponent = defineComponent({
|
|||||||
page: String
|
page: String
|
||||||
},
|
},
|
||||||
template: `
|
template: `
|
||||||
<div>
|
<div>
|
||||||
<h3>You're looking at the <strong>{{ page }}</strong> page</h3>
|
<h3>You're looking at the <strong>{{ page }}</strong> page</h3>
|
||||||
<p>Has metaInfo been updated due to navigation? {{ metaUpdated }}</p>
|
<p>Has metaInfo been updated due to navigation? {{ metaUpdated }}</p>
|
||||||
</div>`,
|
</div>
|
||||||
|
`,
|
||||||
setup (props) {
|
setup (props) {
|
||||||
const state = reactive({
|
const state = reactive({
|
||||||
date: null,
|
date: null,
|
||||||
|
|||||||
+20
-20
@@ -48,59 +48,59 @@
|
|||||||
"vue": "next"
|
"vue": "next"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@babel/core": "^7.10.5",
|
"@babel/core": "^7.11.1",
|
||||||
"@babel/node": "^7.10.5",
|
"@babel/node": "^7.10.5",
|
||||||
"@babel/preset-env": "^7.10.4",
|
"@babel/preset-env": "^7.11.0",
|
||||||
"@babel/preset-typescript": "^7.10.4",
|
"@babel/preset-typescript": "^7.10.4",
|
||||||
"@nuxtjs/eslint-config-typescript": "^2.0.0",
|
"@nuxtjs/eslint-config-typescript": "^3.0.0",
|
||||||
"@types/webpack": "^4.41.21",
|
"@types/webpack": "^4.41.21",
|
||||||
"@types/webpack-env": "^1.15.2",
|
"@types/webpack-env": "^1.15.2",
|
||||||
"@typescript-eslint/eslint-plugin": "^3.7.0",
|
"@typescript-eslint/eslint-plugin": "^3.8.0",
|
||||||
"@typescript-eslint/parser": "^3.7.0",
|
"@typescript-eslint/parser": "^3.8.0",
|
||||||
"@vue/compiler-sfc": "^3.0.0-rc.4",
|
"@vue/compiler-sfc": "^3.0.0-rc.5",
|
||||||
"@vue/server-renderer": "^3.0.0-rc.4",
|
"@vue/server-renderer": "^3.0.0-rc.5",
|
||||||
"@vue/server-test-utils": "^1.0.3",
|
"@vue/server-test-utils": "^1.0.3",
|
||||||
"@vue/test-utils": "^1.0.3",
|
"@vue/test-utils": "^1.0.3",
|
||||||
"@wishy-gift/html-include-chunks-webpack-plugin": "^0.1.5",
|
"@wishy-gift/html-include-chunks-webpack-plugin": "^0.1.5",
|
||||||
"babel-jest": "^26.1.0",
|
"babel-jest": "^26.2.2",
|
||||||
"babel-loader": "^8.1.0",
|
"babel-loader": "^8.1.0",
|
||||||
"babel-plugin-dynamic-import-node": "^2.3.3",
|
"babel-plugin-dynamic-import-node": "^2.3.3",
|
||||||
"browserstack-local": "^1.4.5",
|
"browserstack-local": "^1.4.5",
|
||||||
"chromedriver": "^84.0.1",
|
"chromedriver": "^84.0.1",
|
||||||
"codecov": "^3.7.2",
|
"codecov": "^3.7.2",
|
||||||
"consola": "^2.14.0",
|
"consola": "^2.15.0",
|
||||||
"eslint": "^7.5.0",
|
"eslint": "^7.6.0",
|
||||||
"express-urlrewrite": "^1.3.0",
|
"express-urlrewrite": "^1.3.0",
|
||||||
"geckodriver": "^1.19.1",
|
"geckodriver": "^1.20.0",
|
||||||
"html-webpack-plugin": "^4.3.0",
|
"html-webpack-plugin": "^4.3.0",
|
||||||
"jest": "^26.1.0",
|
"jest": "^26.2.2",
|
||||||
"jest-environment-jsdom": "^26.1.0",
|
"jest-environment-jsdom": "^26.2.0",
|
||||||
"jest-environment-jsdom-global": "^2.0.4",
|
"jest-environment-jsdom-global": "^2.0.4",
|
||||||
"jsdom": "^16.3.0",
|
"jsdom": "^16.4.0",
|
||||||
"lodash": "^4.17.19",
|
"lodash": "^4.17.19",
|
||||||
"node-env-file": "^0.1.8",
|
"node-env-file": "^0.1.8",
|
||||||
"puppeteer-core": "^5.2.1",
|
"puppeteer-core": "^5.2.1",
|
||||||
"rimraf": "^3.0.2",
|
"rimraf": "^3.0.2",
|
||||||
"rollup": "^2.23.0",
|
"rollup": "^2.23.1",
|
||||||
"rollup-plugin-babel": "^4.4.0",
|
"rollup-plugin-babel": "^4.4.0",
|
||||||
"rollup-plugin-commonjs": "^10.1.0",
|
"rollup-plugin-commonjs": "^10.1.0",
|
||||||
"rollup-plugin-json": "^4.0.0",
|
"rollup-plugin-json": "^4.0.0",
|
||||||
"rollup-plugin-node-resolve": "^5.2.0",
|
"rollup-plugin-node-resolve": "^5.2.0",
|
||||||
"rollup-plugin-replace": "^2.2.0",
|
"rollup-plugin-replace": "^2.2.0",
|
||||||
"rollup-plugin-terser": "^6.1.0",
|
"rollup-plugin-terser": "^7.0.0",
|
||||||
"rollup-plugin-typescript2": "^0.27.1",
|
"rollup-plugin-typescript2": "^0.27.2",
|
||||||
"selenium-webdriver": "^4.0.0-alpha.7",
|
"selenium-webdriver": "^4.0.0-alpha.7",
|
||||||
"standard-version": "^8.0.2",
|
"standard-version": "^8.0.2",
|
||||||
"tib": "^0.7.4",
|
"tib": "^0.7.4",
|
||||||
"ts-jest": "^26.1.3",
|
"ts-jest": "^26.1.4",
|
||||||
"ts-loader": "^8.0.1",
|
"ts-loader": "^8.0.2",
|
||||||
"ts-node": "^8.10.2",
|
"ts-node": "^8.10.2",
|
||||||
"typescript": "^3.9.7",
|
"typescript": "^3.9.7",
|
||||||
"vue": "next",
|
"vue": "next",
|
||||||
"vue-jest": "^3.0.6",
|
"vue-jest": "^3.0.6",
|
||||||
"vue-loader": "^16.0.0-beta.2",
|
"vue-loader": "^16.0.0-beta.2",
|
||||||
"vue-router": "next",
|
"vue-router": "next",
|
||||||
"webpack": "^4.44.0",
|
"webpack": "^4.44.1",
|
||||||
"webpack-bundle-analyzer": "^3.8.0",
|
"webpack-bundle-analyzer": "^3.8.0",
|
||||||
"webpack-cli": "^3.3.12",
|
"webpack-cli": "^3.3.12",
|
||||||
"webpack-dev-server": "^3.11.0",
|
"webpack-dev-server": "^3.11.0",
|
||||||
|
|||||||
+3
-3
@@ -1,6 +1,6 @@
|
|||||||
import { hasOwn } from '@vue/shared'
|
import { hasOwn } from '@vue/shared'
|
||||||
import { clone } from '../utils'
|
import { clone } from '../utils'
|
||||||
import { ActiveNode, MetaContext, PathSegments, ShadowNode } from '../types'
|
import { ActiveNode, GetActiveNode, MetaContext, PathSegments, ShadowNode, GetShadowNodes } from '../types'
|
||||||
|
|
||||||
export function resolveActive (
|
export function resolveActive (
|
||||||
context: MetaContext,
|
context: MetaContext,
|
||||||
@@ -13,8 +13,8 @@ export function resolveActive (
|
|||||||
|
|
||||||
if (shadowParent[key].length > 1) {
|
if (shadowParent[key].length > 1) {
|
||||||
// Is using freeze useful? Idea is to prevent the user from messing with these options by mistake
|
// Is using freeze useful? Idea is to prevent the user from messing with these options by mistake
|
||||||
const getShadow = () => Object.freeze(clone(shadowParent[key]))
|
const getShadow: GetShadowNodes = () => Object.freeze(clone(shadowParent[key]))
|
||||||
const getActive = () => Object.freeze(clone(activeParent[key]))
|
const getActive: GetActiveNode = () => Object.freeze(clone(activeParent[key]))
|
||||||
|
|
||||||
value = context.manager.resolver.resolve(
|
value = context.manager.resolver.resolve(
|
||||||
key,
|
key,
|
||||||
|
|||||||
+6
-5
@@ -1,4 +1,4 @@
|
|||||||
import { isPlainObject, hasOwn } from '@vue/shared'
|
import { isPlainObject, /**/ hasOwn } from '@vue/shared'
|
||||||
import { ActiveNode, MetaContext, PathSegments, ShadowNode } from '../types'
|
import { ActiveNode, MetaContext, PathSegments, ShadowNode } from '../types'
|
||||||
import { shadow, active } from './globals'
|
import { shadow, active } from './globals'
|
||||||
import { resolveActive } from './resolve'
|
import { resolveActive } from './resolve'
|
||||||
@@ -15,7 +15,7 @@ export function set (
|
|||||||
// shadow & active should always be in sync
|
// shadow & active should always be in sync
|
||||||
// if not we have bigger fish to fry
|
// if not we have bigger fish to fry
|
||||||
if (!shadowParent[key]) {
|
if (!shadowParent[key]) {
|
||||||
shadowParent[key] = {}
|
shadowParent[key] = []
|
||||||
activeParent[key] = {}
|
activeParent[key] = {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -26,7 +26,7 @@ export function set (
|
|||||||
activeParent[key],
|
activeParent[key],
|
||||||
pathSegments
|
pathSegments
|
||||||
)
|
)
|
||||||
}
|
}/**/
|
||||||
|
|
||||||
let idx = -1
|
let idx = -1
|
||||||
if (!shadowParent[key]) {
|
if (!shadowParent[key]) {
|
||||||
@@ -34,7 +34,7 @@ export function set (
|
|||||||
} else {
|
} else {
|
||||||
// check if we already have a value listed for this element for this context
|
// check if we already have a value listed for this element for this context
|
||||||
idx = shadowParent[key].findIndex(
|
idx = shadowParent[key].findIndex(
|
||||||
({ context: $context }: { context: MetaContext }) => $context === context
|
({ context: shadowContext }: { context: MetaContext }) => shadowContext === context
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -68,12 +68,13 @@ export function setByObject (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (isPlainObject(shadowParent[key])) {
|
if (isPlainObject(shadowParent[key])) {
|
||||||
|
console.log('HERERER')
|
||||||
setByObject(context, {}, shadowParent[key], activeParent[key], [
|
setByObject(context, {}, shadowParent[key], activeParent[key], [
|
||||||
...pathSegments,
|
...pathSegments,
|
||||||
key
|
key
|
||||||
])
|
])
|
||||||
continue
|
continue
|
||||||
}
|
} /**/
|
||||||
|
|
||||||
set(context, key, undefined, shadowParent, activeParent, [
|
set(context, key, undefined, shadowParent, activeParent, [
|
||||||
...pathSegments,
|
...pathSegments,
|
||||||
|
|||||||
+4
-4
@@ -1,8 +1,8 @@
|
|||||||
import { App } from 'vue'
|
import { App } from 'vue'
|
||||||
import { isFunction } from '@vue/shared'
|
import { isFunction } from '@vue/shared'
|
||||||
import { applyMetaPlugin } from './install'
|
import { applyMetaPlugin } from './install'
|
||||||
import * as deepestResolver from './resolvers/deepest'
|
// import * as deepestResolver from './resolvers/deepest'
|
||||||
import { Config, ManagerResolverObject, ActiveResolverObject, MetaContext, PathSegments } from './types'
|
import { Config, ManagerResolverObject, GetActiveNode, ActiveResolverObject, MetaContext, PathSegments, GetShadowNodes } from './types'
|
||||||
|
|
||||||
export type Manager = {
|
export type Manager = {
|
||||||
readonly config: Config
|
readonly config: Config
|
||||||
@@ -11,7 +11,7 @@ export type Manager = {
|
|||||||
install(app: App): void
|
install(app: App): void
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createManager (config: Config, resolver: ActiveResolverObject = deepestResolver): Manager {
|
export function createManager (config: Config, resolver: ActiveResolverObject): Manager {
|
||||||
// TODO: validate resolver
|
// TODO: validate resolver
|
||||||
const manager: Manager = {
|
const manager: Manager = {
|
||||||
resolver: {
|
resolver: {
|
||||||
@@ -22,7 +22,7 @@ export function createManager (config: Config, resolver: ActiveResolverObject =
|
|||||||
|
|
||||||
resolver.setup(context)
|
resolver.setup(context)
|
||||||
},
|
},
|
||||||
resolve (key: string, pathSegments: PathSegments, getShadow, getActive) {
|
resolve (key: string, pathSegments: PathSegments, getShadow: GetShadowNodes, getActive: GetActiveNode) {
|
||||||
if (!resolver) {
|
if (!resolver) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|||||||
+2
-8
@@ -7,17 +7,11 @@ interface Target extends MetainfoInput {
|
|||||||
__vm_proxy?: any // eslint-disable-line camelcase
|
__vm_proxy?: any // eslint-disable-line camelcase
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createProxy (
|
export function createProxy (target: Target, handler: ProxyHandler<object>): Target {
|
||||||
target: Target,
|
|
||||||
handler: ProxyHandler<object>
|
|
||||||
): Target {
|
|
||||||
return markRaw(new Proxy(target, handler))
|
return markRaw(new Proxy(target, handler))
|
||||||
}
|
}
|
||||||
|
|
||||||
export function createHandler (
|
export function createHandler (context: MetaContext, pathSegments: PathSegments = []): ProxyHandler<object> {
|
||||||
context: MetaContext,
|
|
||||||
pathSegments: PathSegments = []
|
|
||||||
): ProxyHandler<object> {
|
|
||||||
return {
|
return {
|
||||||
get (target: object, key: string, receiver: object) {
|
get (target: object, key: string, receiver: object) {
|
||||||
const value = Reflect.get(target, key, receiver)
|
const value = Reflect.get(target, key, receiver)
|
||||||
|
|||||||
+4
-4
@@ -42,7 +42,7 @@ export function renderMeta (
|
|||||||
data: TODO,
|
data: TODO,
|
||||||
config: TODO
|
config: TODO
|
||||||
): void | RenderedMetainfo | RenderedMetainfoNode {
|
): void | RenderedMetainfo | RenderedMetainfoNode {
|
||||||
console.info('renderMeta', key, data, config)
|
// console.info('renderMeta', key, data, config)
|
||||||
|
|
||||||
if (config.attributesFor) {
|
if (config.attributesFor) {
|
||||||
return renderAttributes(context, key, data, config)
|
return renderAttributes(context, key, data, config)
|
||||||
@@ -61,7 +61,7 @@ export function renderGroup (
|
|||||||
data: TODO,
|
data: TODO,
|
||||||
config: TODO
|
config: TODO
|
||||||
): RenderedMetainfo | RenderedMetainfoNode {
|
): RenderedMetainfo | RenderedMetainfoNode {
|
||||||
console.info('renderGroup', key, data, config)
|
// console.info('renderGroup', key, data, config)
|
||||||
|
|
||||||
if (isArray(data)) {
|
if (isArray(data)) {
|
||||||
if (__DEV__) {
|
if (__DEV__) {
|
||||||
@@ -101,7 +101,7 @@ export function renderTag (
|
|||||||
config: TODO = {},
|
config: TODO = {},
|
||||||
groupConfig?: GroupConfig
|
groupConfig?: GroupConfig
|
||||||
): RenderedMetainfo | RenderedMetainfoNode {
|
): RenderedMetainfo | RenderedMetainfoNode {
|
||||||
console.info('renderTag', key, data, config, groupConfig)
|
// console.info('renderTag', key, data, config, groupConfig)
|
||||||
|
|
||||||
const contentAttributes = ['content', 'json', 'rawContent']
|
const contentAttributes = ['content', 'json', 'rawContent']
|
||||||
const getConfig = (key: string) => getConfigByKey([tag, config.tag], key, config)
|
const getConfig = (key: string) => getConfigByKey([tag, config.tag], key, config)
|
||||||
@@ -234,7 +234,7 @@ export function renderAttributes (
|
|||||||
data: TODO,
|
data: TODO,
|
||||||
config: TODO = {}
|
config: TODO = {}
|
||||||
): void {
|
): void {
|
||||||
console.info('renderAttributes', key, data, config)
|
// console.info('renderAttributes', key, data, config)
|
||||||
|
|
||||||
const { attributesFor } = config
|
const { attributesFor } = config
|
||||||
|
|
||||||
|
|||||||
@@ -1,15 +1,56 @@
|
|||||||
import {
|
import {
|
||||||
ActiveNode,
|
// ActiveNode,
|
||||||
/* ActiveResolverSetup, ActiveResolverMethod, */ MetaContext,
|
/* ActiveResolverSetup, ActiveResolverMethod, */ MetaContext,
|
||||||
PathSegments,
|
PathSegments,
|
||||||
ShadowNode
|
ShadowNode,
|
||||||
|
GetActiveNode,
|
||||||
|
GetShadowNodes
|
||||||
} from '../types'
|
} from '../types'
|
||||||
|
|
||||||
export function setup (context: MetaContext): void {}
|
interface DeepestResolverMetaContext extends MetaContext {
|
||||||
|
depth?: number
|
||||||
|
}
|
||||||
|
|
||||||
|
export function setup (context: DeepestResolverMetaContext): void {
|
||||||
|
let depth: number = 0
|
||||||
|
|
||||||
|
if (context.vm) {
|
||||||
|
let { vm } = context
|
||||||
|
|
||||||
|
do {
|
||||||
|
depth++
|
||||||
|
vm = vm.parent
|
||||||
|
} while (vm && vm !== vm.root)
|
||||||
|
}
|
||||||
|
|
||||||
|
context.depth = depth
|
||||||
|
}
|
||||||
|
|
||||||
export function resolve (
|
export function resolve (
|
||||||
key: string,
|
key: string,
|
||||||
pathSegments: PathSegments,
|
_pathSegments: PathSegments,
|
||||||
shadow: ShadowNode,
|
getOptions: GetShadowNodes,
|
||||||
active: ActiveNode
|
getCurrentValue: GetActiveNode
|
||||||
): any {}
|
): any {
|
||||||
|
let resolvedOption: ShadowNode | void
|
||||||
|
|
||||||
|
const options = getOptions()
|
||||||
|
|
||||||
|
for (const option of options) {
|
||||||
|
if (!resolvedOption || resolvedOption.context.depth < option.context.depth) {
|
||||||
|
resolvedOption = option
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
console.log(
|
||||||
|
'DEEPEST.RESOLVE',
|
||||||
|
key,
|
||||||
|
getCurrentValue(),
|
||||||
|
options.map(({ value }) => value)
|
||||||
|
)
|
||||||
|
|
||||||
|
if (resolvedOption) {
|
||||||
|
console.log(resolvedOption.value)
|
||||||
|
return resolvedOption.value
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+11
-3
@@ -34,7 +34,7 @@ export interface MetainfoActive {
|
|||||||
|
|
||||||
export type MetaContext = {
|
export type MetaContext = {
|
||||||
id: string | symbol
|
id: string | symbol
|
||||||
vm?: ComponentInternalInstance | null
|
vm?: ComponentInternalInstance
|
||||||
manager: Manager
|
manager: Manager
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -42,8 +42,8 @@ export type ActiveResolverSetup = (context: MetaContext) => void
|
|||||||
export type ActiveResolverMethod = (
|
export type ActiveResolverMethod = (
|
||||||
key: string,
|
key: string,
|
||||||
pathSegments: PathSegments,
|
pathSegments: PathSegments,
|
||||||
shadow: ShadowNode,
|
shadow: GetShadowNodes,
|
||||||
active: ActiveNode
|
active: GetActiveNode
|
||||||
) => any
|
) => any
|
||||||
|
|
||||||
export interface ActiveResolverObject {
|
export interface ActiveResolverObject {
|
||||||
@@ -63,3 +63,11 @@ export interface ShadowNode {
|
|||||||
export interface ActiveNode {
|
export interface ActiveNode {
|
||||||
[key: string]: TODO
|
[key: string]: TODO
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface GetShadowNodes {
|
||||||
|
(): Array<ShadowNode>
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface GetActiveNode {
|
||||||
|
(): ActiveNode
|
||||||
|
}
|
||||||
|
|||||||
+1
-1
@@ -20,7 +20,7 @@ export function useMeta (obj: MetainfoInput, manager?: Manager) {
|
|||||||
|
|
||||||
const context: MetaContext = {
|
const context: MetaContext = {
|
||||||
id: PolySymbol(`context ${contextCounter++}`),
|
id: PolySymbol(`context ${contextCounter++}`),
|
||||||
vm,
|
vm: vm || undefined,
|
||||||
manager
|
manager
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user